What You'll Build in this Workshop:

Full Application

In order to create a Flutter project for the first time, navigate to the folder location where you want the project to reside, and run the command flutter create plus the name of the project, as such:

flutter create <YOURNAME>_portfolio

This will create a project called YOURNAME_portfolio which will be the starting point for this project.

Navigate to the root of the project by running the command cd YOURNAME_portfolio since that's where the main files are located.

The project is ready, so let's dive right in!

With the project ready, let's locate the main.dart file, which is the starting file of your Flutter app. It should be inside the root's folder, inside a subfolder called lib.

First things first, in the main.dart file, clean the contents of this file as you get some boilerplate code that we don't want. Make sure you're importing the Material library as the first line in the file, as such:

import 'package:flutter/material.dart';

Let's lay down the root widget of this app. Implement the first method of the app, the void main() method, which is the most important method in a Flutter app as it bootstraps it and installs the root widget. Inside the main method, call the first framework method, the runApp method, and inside it, install the root widget (no worries, it doesn't exist yet - still go ahead and add it) which will be called PersonalPortfolioApp:

void main() {
  runApp(const PersonalPortfolioApp());
}

Creating a custom widget is a matter of just creating a class that extends either StatefulWidget or StatelessWidget. In our case, we want this widget to be Stateless as it will not maintain state and will only render the root widget. Follow the links for more info on StatefulWidget and StatelessWidget. Let's call it PersonalPortfolioApp and make it extend StatelessWidget.

Override its build method to let the Flutter framework know to call this method and build the widget hiearchy returned by this method. Return an object of type Widget and take in a BuildContext reference, as such:

class PersonalPortfolioApp extends StatelessWidget {

  const PersonalPortfolioApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    // TODO: rest of the code here
  }
}

Inside the build method, return a widget of type MaterialApp - this is the widget that represents the Material library and all of the styles related to it, which will trickle down the hierarchy when placed this high in the hierarchy.

Set the following properties as follows:

Your code should look like this:

// INSIDE THE BUILD METHOD...

return const MaterialApp(
  debugShowCheckedModeBanner: false,
  home: Scaffold(
    body: Center(
      child: PersonalPortfolio(),
    ),
  ),
);

Let's proceed with creating the PersonalPortfolio custom widget as a StatefulWidget.

We create the PersonalPortfolio widget as a StatefulWidget this time around, since we will be rebuilding it rapidly as its properties change as a result of an animation we'll create in just a minute - this is one of the cases for having a StatefulWidget; other cases involve for example if we want to reflect a change in some piece of data being provided to this widget, etc.

Proceed to create a class called PersonalPortfolio and make it extend StatefulWidget. Note that creating a StatefulWidget is a two-step process: first create the StatefulWidget class, which overrides its createState method and returns an instance of State, strongly-typed to the StatefulWidget class, as such:

class PersonalPortfolio extends StatefulWidget {

  const PersonalPortfolio({Key? key}) : super(key: key);

  @override
  PersonalPortfolioState createState() => PersonalPortfolioState();
}

Then create the corresponding State class, called PersonalPortfolioState, which extends State<PersonalPortfolio>, right below it; this is where the state will be maintained as the widget rebuilds. Override its build method, returning a Widget instance and passing a BuildContext instance to it:

class PersonalPortfolioState extends State<PersonalPortfolio> {

  @override
  Widget build(BuildContext context) {
    // TODO: rest of the code here
  }
}

Now let's focus on the structure of the PersonalPortfolio widget.

The following is a schematics view of what we'll be building in this section:

PersonalPortfolio

Let's dig right in!

At the top of the PersonalPortfolioState class, create a local property called appColor, type Color and final; assign your favorite color from the predefined list of colors available in Flutter - besides, this is your portfolio so make it personal!. I'll set it to be Colors.blueAccent - one of my favorites:

final Color appColor = Colors.blueAccent;

We'll build the structure by starting at the top, returning a Center widget, wrapping a Column widget with the following specs:

Your code should look like this inside the build method:

// INSIDE THE BUILD METHOD...
return Center(
  child: Column(
    mainAxisSize: MainAxisSize.min,
    mainAxisAlignment: MainAxisAlignment.center,
    crossAxisAlignment: CrossAxisAlignment.center,
    children: []
  )
);

Let's continue by creating the container that will enclose the avatar image. But before we start, go and grab an image of yourself (i.e. from your Github profile, from your Gmail profile).

Go, I'll wait.

Did you get it? If not, this is how you get it from your Gmail profile:

PersonalPortfolio

PersonalPortfolio

Now, after copying the image address, hold on to it on a variable at the top of the State class, which we'll call avatarImg, as such:

final String avatarImg = '<YOUR_IMAGE_PATH>';
// in my case: https://lh3.googleusercontent.com/a-/AFdZucrm0yVENa6ZYGrpjjSpSVKV69oQik_dCg6G86BrYVA=s288-p-rw-no

Now let's create the Container widget, with the following specs:

Your code should look like this afterwards:

Container(
  width: 100,
  height: 100,
  margin: const EdgeInsets.only(bottom: 20),
  decoration: BoxDecoration(
    borderRadius: BorderRadius.circular(50),
    image: DecorationImage(
      image: NetworkImage(avatarImg),
      fit: BoxFit.cover
    ),
    border: Border.all(
      color: appColor,
      width: 8
    )
  )
)

Right under this Container, proceed to add two Text widgets with the following specs:

Your structure should look like this:

// UNDER THE ABOVE CONTAINER...

Text('Roman Jaquez', 
  style: TextStyle(
    color: appColor, 
    fontSize: 20, 
    fontWeight: FontWeight.bold
  )
),
const Text('Flutter GDE / Cloud Architect'),
const SizedBox(height: 20),

Last in the structure, let's add a TextButton widget, in which we'll create a little structure representing a piece of contact information (our email), as such:

Your TextButton should look like this in the end:

TextButton(
  onPressed: () {},
  child: Row(
    mainAxisAlignment: MainAxisAlignment.center,
    mainAxisSize: MainAxisSize.min,
    children: [
      Icon(Icons.email, color: appColor),
      const SizedBox(width: 10),
      Text('romanejaquez@gmail.com', style: TextStyle(color: appColor))
    ]
  )
),

Rebuild your app and verify the basic structure is in place!

At this point you're good - if you want to skip the next step, it's up to you - but the next one is pretty interesting: it's all about animating your widgets! Proceed with caution as your mind will be blown - don't say I didn't warn you!

We'll be dealing with one of most exciting features in Flutter, which is its capabilities of implementing and achieving those buttery-smooth 60 fps animations that will give your apps an extra punch and an edge over others.

Let's proceed!

We'll add a glowing effect to the avatar image we just created inside a Container widget. We will be using explicit animations for this, as we'd like more control over the animation sequence.

Start by adding a mixin, which is a way to add further capabilities to your existing widget classes via special constructs without incurring in multiple inheritance. The mixin is called TickerProviderStateMixin and you implement it by adding at the end of the class definition with the with keyword, as in:

class PersonalPortfolioState extends State<PersonalPortfolio> with TickerProviderStateMixin {

  //... rest of the code omitted for brevity

}

In order to control the animation's lifecycle, play the animation, define the upper and lower bounds of the animation, we need an AnimationController instance. Create a late AnimationController reference at the top of the State class, call it ctrl.

late AnimationController ctrl;

Override the State's initState method; this is where you'll instantiate the ctrl AnimationController instance. To the instance, set its vsync to this, and a constant duration of 2 seconds. To the resulting instance, call its repeat method; this means the animation, wherever applied, will last 2 seconds, then repeat itself infinitely unless explicitly stopped.

Your initState method should look as follows:

@override
void initState() {
  super.initState();
  ctrl = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 2)
  )..repeat();
}

As a best practice, don't forget to dispose of the controller used in the animation in the State class' dispose method, as such:

@override
void dispose() {
  ctrl.dispose();
  super.dispose();
}

With this in place, let's do some refactoring to our widget structure to add the glowing animation. This animation will be handled by a Container widget that will be placed right behind the existing Container holding the image, to which we'll attach the Animation controller with a scaling and a fading transition, causing the glowing effect. Let's proceed.

Wrap the existing Container widget holding the image inside a Stack widget and set it as its child; this is what will cause the stacking of the two containers in question. Inside the Stack children property, add another Container on top of the existing Container with the following specs:

The structure around the existing Container should look like this:

//... rest of the code omitted for brevity...

Stack(
  children: [
    // the glowing circle
    Container(
      width: 100,
      height: 100,
      decoration: BoxDecoration(
        color: appColor,
        borderRadius: BorderRadius.circular(50),
      )
    ),
    // the avatar image container
    Container(
      width: 100,
      height: 100,
      margin: const EdgeInsets.only(bottom: 20),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(50),
        image: DecorationImage(
          image: NetworkImage(avatarImg),
          fit: BoxFit.cover
        ),
        border: Border.all(
          color: appColor,
          width: 8
        )
      )
    )
  ]
),

Now let's apply a scale transition animation to the newly added Container widget by wrapping it inside a ScaleTransition widget and setting the following properties:

Your code should look as follows:

ScaleTransition(
  scale: Tween<double>(begin: 1.0, end: 1.5).
  animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
  child: Container(
    width: 100,
    height: 100,
    decoration: BoxDecoration(
      color: Colors.blueAccent,
      borderRadius: BorderRadius.circular(50),
    )
  ) 
) 

To top it off, add a fading transition animation by wrapping the existing ScaleTransition widget into yet another widget, a FadeTransition widget; set its properties as such:

In the end, your code should look like:

FadeTransition(
  opacity: Tween<double>(begin: 1.0, end: 0.0)
  .animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
  child: ScaleTransition(
    //.. rest of the code omitted
  )
)

Take it for a spin and you should see the glowing animation effect right from behind the avatar image - pretty neat!

PersonalPortfolio

You can implement animations to whole widget structures as well! Let's try implementing an animation to the whole portfolio card widget we've created.

Let's start!

We'll proceed the same way we did with the glowing effect we applied on the Container widget from before.

Let's create one additional AnimationController as we want to control the animation and give it a different duration speed. At the top, right below the existing one, create a new AnimationController called contentCtrl:

late AnimationController contentCtrl;

In the same initState method, initialize that instance, feeding the this reference to the vsync parameter, and as its duration, set it to be a const Duration with a 3-second duration. To the resulting instance, call the forward method, as we only want it to be executed in a forward fashion only once, as such:

@override
void initState() {
  
  //... previous code omitted for brevity
  
  contentCtrl = AnimationController(
    vsync: this,
    duration: const Duration(seconds: 3)
  )..forward();
}

As customary, call dispose on its instance in the widget's dispose:

@override
void dispose() {

  //... previous code omitted for brevity

  contentCtrl.dispose();
}

Since we want our portfolio widget to slide from the bottom, wrap the whole structure (the Center widget containing the whole Column) inside a SlideTransitionWidget; to make it slide from the bottom up, set its position property to be an Animation type Offset, generated from a Tween instance's animate method of the same type, as follows:

// INSIDE THE BUILD METHOD...
 
return SlideTransition(
  position: Tween<Offset>(begin: const Offset(0.0, 0.125), end: Offset.zero)
  .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
  child: Center(
    // ... rest of the code omitted for brevity
  )
);

We also want to apply a fading animation by leveraging the same animation controller but applied to a FadeTransition widget. Wrap the existing SlideTransition widget inside a FadeTransition widget and set its opacity property accordingly:

return FadeTransition(
  opacity: Tween<double>(begin: 0.0, end: 1.0)
  .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
  child: SlideTransition(
    // ... rest of the code omitted for brevity
  )
);

Now, rebuild and reload your Flutter web app and you should see it slide from the bottom of the screen in a smooth fading animation - nice and smooth!

Here's the complete code with animations and all - enjoy!

Complete Code

import 'package:flutter/material.dart';

void main() {
  runApp(const PersonalPortfolioApp());
}

class PersonalPortfolioApp extends StatelessWidget {

  const PersonalPortfolioApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: PersonalPortfolio(),
        ),
      ),
    );
  }
}

class PersonalPortfolio extends StatefulWidget {

  const PersonalPortfolio({Key? key}) : super(key: key);

  
  @override
  PersonalPortfolioState createState() => PersonalPortfolioState();
}

class PersonalPortfolioState extends State<PersonalPortfolio> with TickerProviderStateMixin {
  
  final Color appColor = Colors.blueAccent;
  final String avatarImg = 'https://lh3.googleusercontent.com/a-/AFdZucrm0yVENa6ZYGrpjjSpSVKV69oQik_dCg6G86BrYVA=s288-p-rw-no';

  late AnimationController ctrl;
  late AnimationController contentCtrl;
  
  @override
  void initState() {
    super.initState();
    ctrl = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2)
    )..repeat();
    
    contentCtrl = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 3)
    )..forward();
  }

  @override
  void dispose() {
    ctrl.dispose();
    contentCtrl.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: Tween<double>(begin: 0.0, end: 1.0)
      .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
      child: SlideTransition(
      position: Tween<Offset>(begin: const Offset(0.0, 0.125), end: Offset.zero)
      .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Stack(
              children: [
                FadeTransition(
                  opacity: Tween<double>(begin: 1.0, end: 0.0)
                  .animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
                  child: ScaleTransition(
                  scale: Tween<double>(begin: 1.0, end: 1.5).
                  animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: appColor,
                      borderRadius: BorderRadius.circular(50),
                    )
                  ) 
                ) 
                ),
                Container(
                  width: 100,
                  height: 100,
                  margin: const EdgeInsets.only(bottom: 20),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(50),
                    image: DecorationImage(
                      image: NetworkImage(avatarImg),
                      fit: BoxFit.cover
                    ),
                    border: Border.all(
                      color: appColor,
                      width: 8
                    )
                  )
                )
              ] 
            ),
            Text('Roman Jaquez', 
              style: TextStyle(
                color: appColor, 
                fontSize: 20, 
                fontWeight: FontWeight.bold
              )
            ),
            const Text('Flutter GDE / Cloud Architect'),
            const SizedBox(height: 20),
            TextButton(
              onPressed: () {},
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(Icons.email, color: appColor),
                  const SizedBox(width: 10),
                  Text('romanejaquez@gmail.com', style: TextStyle(color: appColor))
                ]
              )
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: () {},
              child: Row(
                mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Icon(Icons.language, color: Colors.blueAccent),
                SizedBox(width: 10),
                Text('romanjustcodes.web.app', style: TextStyle(color: Colors.blueAccent))
              ]
            )
            )
          ]
        )
      )
    )
    );
  }
}


It's time to make our Flutter web app masterpiece available for the whole world to appreciate, by publishing it to Firebase Hosting - a production-grade web content hosting for developers. With a single command, you can quickly deploy web apps and serve both static and dynamic content to a global CDN (content delivery network).

For this exercise, we will use both the Firebase Console, a web-based GUI for managing your Firebase projects as well as the Firebase CLI, which provides a set of command-line-based tools for managing, viewing and deploying to Firebase projects.

Let's first create our first Firebase project via the Console.

Navigate to console.firebase.google.com which is the web-based tool for managing your Firebase project.

To create your first project, click on the "Create Project" button.

PersonalPortfolio

Go through the steps on creating your project, starting with a valid project name (ie. since this will be a personal portfolio web app, you can call it "yourname-portfolio-app" - hopefully is not taken!). Make sure to accept the terms and usage:

PersonalPortfolio

Disable the toggle for "Enable Google Analytics for this project" - we don't need it for our case, but you can enable it later:

PersonalPortfolio

And with that, your project starts to get provisioned in the Google Cloud; please wait until it gets created:

PersonalPortfolio

Your project is ready! click "Continue":

PersonalPortfolio

In the landing page of your Firebase console, locate the "Hosting" menu item on the left hand side. Go ahead and navigate to it:

PersonalPortfolio

This should take you to the Hosting section of the Firebase console, where you manage your hosting configuration. Click on "Get Started" to proceed:

PersonalPortfolio

The next steps are more explanatory to tell you what things you need to configure in your machine to deploy your web app to Firebase Hosting and the tools you need to install to accomplish that. First step instructs you to install the Firebase CLI:

PersonalPortfolio

Next step shows you how to authenticate against Firebase from the CLI and how to initialize your environment and configure it for Firebase deployments:

PersonalPortfolio

And the last step shows you the command to run when ready to deploy your project to Firebase Hosting. Afterwards, click "Continue to console" to proceed:

PersonalPortfolio

With that in place, let's proceed to configure the Firebase CLI.

If you haven't installed it, go ahead and run the following installation command:

npm install -g firebase-tools

After installing the CLI, you must authenticate. Run the following command:

firebase login

This should initiate the process and present you with the first prompt, asking you to allow Firebase to collect CLI reporting information. You can select either option - go ahead and type ‘Y':

PersonalPortfolio

Because you are running this on a machine that has a browser, this automatically launches a browser window where the authentication flow must be completed. Use the same Gmail Account you use to go to the Firebase Console under which you created the project:

PersonalPortfolio

Click on "Allow" to allow the Firebase CLI access to your Google account:

PersonalPortfolio

After successfully allowing and completing the authentication, feel free to close this browser window:

PersonalPortfolio

Going back to the command line, you should see the following message, also confirming successful authentication:

PersonalPortfolio

Initialize the Firebase environment

Proceed to now to run the following command to initialize the project as a Firebase environment:

firebase init

This should present you with a series of prompts to properly configure the project; the first option is the Firebase feature you want to set up; in our case, select the "Hosting: Configure files for Firebase Hosting and (optionally) set up Github Action deploys":

PersonalPortfolio

PersonalPortfolio

Next, select the Firebase project you want to associate this project directory. Select "Use an existing project":

PersonalPortfolio

Then, go ahead and navigate to your particular project.

Next, as the directory that Firebase will use to grab your web-generated files for deployment, set it to be the build/web folder - this is the default location where Flutter web publishes your assets ready to be deployed on a web server:

PersonalPortfolio

Next, make sure to type ‘y' in the option to configure your web app as a single-page app:

PersonalPortfolio

Say ‘N' when it comes to setting up automatic builds and deploys with Github:

PersonalPortfolio

Do not override the existing index.html located in the build/web folder, so say ‘N' for this option:

PersonalPortfolio

After that last option, confirm that you get a message saying "Firebase initialization complete" in the command line:

PersonalPortfolio

Notice a few files that get generated as a result of initializing Firebase in this project: a file called .firebaserc and a firebase.json, which are files containing the configuration collected during init, and needed to connect to Firebase and deploy our web app.

Let's proceed to the next step, which is the actual deployment.

Hosting your Flutter Web App on Firebase: Deployment

Let's now deploy our newly minted Flutter Web App.

Make sure you are at the root of the project where the .firebaserc and a firebase.json are located.

Build your Flutter web app

First, you must build the Flutter web app so it generates web-compatible files out of your Flutter code. Run the following command:

flutter build web --dart-define=BROWSER_IMAGE_DECODING_ENABLED=false --release

Verify that the project has been built by navigating to the build/web folder.

Now, all we need to do is run the following command to deploy your web project to firebase:

firebase deploy

After a little bit, you should get a message confirming that the deployment is complete. The Firebase CLI should generate a Hosting URL, where your web app is deployed. Navigate to that URL and confirm your web page is live and public.

Full Application

And with that, we're done with this codelab for this workshop, where we accomplished the following:

Please don't forget to follow me on social media:

In case you fell behind on this codelab, below is the whole code for this codelab in a way you can copy / paste directly into DartPad:

import 'package:flutter/material.dart';

void main() {
  runApp(const PersonalPortfolioApp());
}

class PersonalPortfolioApp extends StatelessWidget {

  const PersonalPortfolioApp({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const MaterialApp(
      debugShowCheckedModeBanner: false,
      home: Scaffold(
        body: Center(
          child: PersonalPortfolio(),
        ),
      ),
    );
  }
}

class PersonalPortfolio extends StatefulWidget {

  const PersonalPortfolio({Key? key}) : super(key: key);

  
  @override
  PersonalPortfolioState createState() => PersonalPortfolioState();
}

class PersonalPortfolioState extends State<PersonalPortfolio> with TickerProviderStateMixin {
  
  final Color appColor = Colors.blueAccent;
  final String avatarImg = 'https://lh3.googleusercontent.com/a-/AFdZucrm0yVENa6ZYGrpjjSpSVKV69oQik_dCg6G86BrYVA=s288-p-rw-no';

  late AnimationController ctrl;
  late AnimationController contentCtrl;
  
  @override
  void initState() {
    super.initState();
    ctrl = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 2)
    )..repeat();
    
    contentCtrl = AnimationController(
      vsync: this,
      duration: const Duration(seconds: 3)
    )..forward();
  }

  @override
  void dispose() {
    ctrl.dispose();
    contentCtrl.dispose();
    super.dispose();
  }
  
  @override
  Widget build(BuildContext context) {
    return FadeTransition(
      opacity: Tween<double>(begin: 0.0, end: 1.0)
      .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
      child: SlideTransition(
      position: Tween<Offset>(begin: const Offset(0.0, 0.125), end: Offset.zero)
      .animate(CurvedAnimation(parent: contentCtrl, curve: Curves.easeInOut)),
      child: Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Stack(
              children: [
                FadeTransition(
                  opacity: Tween<double>(begin: 1.0, end: 0.0)
                  .animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
                  child: ScaleTransition(
                  scale: Tween<double>(begin: 1.0, end: 1.5).
                  animate(CurvedAnimation(parent: ctrl, curve: Curves.easeInOut)),
                  child: Container(
                    width: 100,
                    height: 100,
                    decoration: BoxDecoration(
                      color: appColor,
                      borderRadius: BorderRadius.circular(50),
                    )
                  ) 
                ) 
                ),
                Container(
                  width: 100,
                  height: 100,
                  margin: const EdgeInsets.only(bottom: 20),
                  decoration: BoxDecoration(
                    borderRadius: BorderRadius.circular(50),
                    image: DecorationImage(
                      image: NetworkImage(avatarImg),
                      fit: BoxFit.cover
                    ),
                    border: Border.all(
                      color: appColor,
                      width: 8
                    )
                  )
                )
              ] 
            ),
            Text('Roman Jaquez', 
              style: TextStyle(
                color: appColor, 
                fontSize: 20, 
                fontWeight: FontWeight.bold
              )
            ),
            const Text('Flutter GDE / Cloud Architect'),
            const SizedBox(height: 20),
            TextButton(
              onPressed: () {},
              child: Row(
                mainAxisAlignment: MainAxisAlignment.center,
                mainAxisSize: MainAxisSize.min,
                children: [
                  Icon(Icons.email, color: appColor),
                  const SizedBox(width: 10),
                  Text('romanejaquez@gmail.com', style: TextStyle(color: appColor))
                ]
              )
            ),
            const SizedBox(height: 10),
            TextButton(
              onPressed: () {},
              child: Row(
                mainAxisSize: MainAxisSize.min,
              mainAxisAlignment: MainAxisAlignment.center,
              children: const [
                Icon(Icons.language, color: Colors.blueAccent),
                SizedBox(width: 10),
                Text('romanjustcodes.web.app', style: TextStyle(color: Colors.blueAccent))
              ]
            )
            )
          ]
        )
      )
    )
    );
  }
}