Who likes to keep his files on the cloud? That’s a very useful technology allowing us to keep our very sensitive files inside a server in a location we don’t even know with a company we don’t trust which is employing people we never met.

Sarcasm apart Google drive – DropBox are very useful tools especially for professionals, just be extra careful on how you manage your accounts, and never trust these services for your confidential files.

Let’s stop talking and into the coding part!

Coding time: 3h53 Minutes.

Source Code: Github.

Home Page:

The most challenging part with this design is how to put two Scrollable widgets one inside another. To be honest I still don’t understand how I managed to do it. I am sure it’s not the best way but hey, it worked.

Let’s start from the top part. The header is pretty straight forward a Column with the first child being a Row containing two Icons ( I didn’t put IconButtons, don’t ask me why ). After that we got two Text widgets greeting the user.

Let’s forget the PageView for now, and go straight to the Contributors list – Co-Owners. There we have a Row, first of its children is an Extended ListView.Builder that contains the CircleAvatar of the users, we use a Container to make the border. Then we have an Add Button to the side I put it outside of the ListView to allow the user to add other Co-Owners directly without having to go to the end of the list.

Now we can take a look at the List of files, which is very simple to do actually. I used a list of type String to store my files, then I used the ListView.builder itemBuilder property to return a Container with a child of type Row hosting our Icon ( Here we only have PDF icons, but you can make it dynamic ), to the right we have a Column hosting the File name and the File Path.

I hope you are not as tired as I am right now because we will be taking a look at the most complicated part of this app.

Let me put the code before your eyes maybe this will help.

PageView.builder( itemCount: 2, itemBuilder: (context, id) { return MyContainer( isActive: id == 0 ? true : false, ); }, ),

Of course, it cannot be that simple, so this is the second part

class MyContainer extends StatelessWidget { final bool isActive; const MyContainer({ Key key, this.isActive, }) : super(key: key); @override Widget build(BuildContext context) { return InkWell( onTap: () { Navigator.pushNamed(context, '/detailsPage'); }, child: Container( margin: isActive ? EdgeInsets.only(bottom: 5) : EdgeInsets.zero, decoration: BoxDecoration( borderRadius: BorderRadius.circular(25), ), child: Stack( children: <Widget>[ Container( padding: EdgeInsets.all(25), margin: isActive ? EdgeInsets.only(bottom: 25, top: 25, left: 15, right: 15) : EdgeInsets.only(bottom: 15, top: 25, left: 15, right: 15), decoration: BoxDecoration( color: isActive ? Colors.blue : Colors.white, borderRadius: BorderRadius.circular(25), boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: isActive ? 13.0 : 5.0, offset: Offset(0, isActive ? 13 : 5.0), ), ], ), child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.center, children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Flexible( child: InkWell( onTap: () {}, child: Container( padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.circular(9), ), child: Icon( Icons.folder_open, color: isActive ? Colors.white54 : Colors.black, ), ), ), ), Flexible( child: Container( padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.circular(9), ), child: Icon( Icons.create_new_folder, color: isActive ? Colors.white54 : Colors.black, ), ), ), Flexible( child: Container( padding: EdgeInsets.all(15), decoration: BoxDecoration( color: Colors.black12, borderRadius: BorderRadius.circular(9), ), child: Icon( Icons.storage, color: isActive ? Colors.white54 : Colors.black, ), ), ), ], ), SizedBox( height: 15, ), Text( "DropBox", style: TextStyle( color: isActive ? Colors.white : Colors.black87, fontSize: 23, fontWeight: FontWeight.bold, ), ), SizedBox( height: 15, ), MyProgressBar(isActive: isActive), ], ), ), Positioned( top: 0, left: 45, child: Container( height: 50, width: 50, padding: EdgeInsets.all(9.0), child: Image.network( "https://upload.wikimedia.org/wikipedia/commons/thumb/7/78/Dropbox_Icon.svg/1101px-Dropbox_Icon.svg.png"), decoration: BoxDecoration( color: Colors.white, shape: BoxShape.circle, boxShadow: [ BoxShadow( color: Colors.black12, blurRadius: 5.0, offset: Offset(0, 5), ), ], ), ), ), ], ), ), ); } }

It looks a bit complicated, doesn’t it?

So to start we have an InkWell and that is allowing us to handle onTap events so that we can go to the other section of the app.

Inside of that, we have the Main Container, I use it to control more easily the position of the cloud hosting provider icon.

Then we have a Stack with the container that is actually hosting the content, you can see a lot of IF STATEMENTS and I do that to differentiate between the selected service and the non-selected one.

For example, we have:

margin: isActive ? EdgeInsets.only(bottom: 25, top: 25, left: 15, right: 15) : EdgeInsets.only(bottom: 15, top: 25, left: 15, right: 15),

I used this to “Lift” the container as you can see there is a difference in the Bottom margin. ( I didn’t find a better way to achieve this ).

Apart from that, it’s only Text widgets and a Row containing a few Icons.

I nearly forgot about the ProgressBar, here it’s a bit special, well, of course, it’s not interactive but you can do that is a few lines of code. But here I used a Custom widget to do that and here it is:

class MyProgressBar extends StatelessWidget { final bool isActive; const MyProgressBar({Key key, this.isActive}) : super(key: key); @override Widget build(BuildContext context) { return Container( child: Column( children: <Widget>[ Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: <Widget>[ Text( "35 GB", style: TextStyle( color: isActive ? Colors.white : Colors.black87, ), ), Text( "75 GB", style: TextStyle( color: isActive ? Colors.white : Colors.black87, ), ) ], ), SizedBox( height: 5, ), LinearProgressIndicator( value: 0.46, backgroundColor: isActive ? Colors.white : Colors.grey[200], valueColor: AlwaysStoppedAnimation<Color>( Colors.yellow, ), ), ], ), ); } }

To make it work just add two final values and calculate the progress and pass it as a value to the LinearProgressIndicator.

There you go you got the first part of the app! Working for both Ios and Android. This is why I really love flutter, with very few lines of code you get a mobile app working on both major mobile platforms.

Details Page:

This article came out to be very long, I think both me and you who are reading this far got a bit tired so we will continue the other part next time God willing.

In the meanwhile, you can help me relax, by inflating my PayPal account with some MONEY $$$.

options Option 1 $1.00 USD Option 2 $5.99 USD Option 3 $10.00 USD

Thank you guys for reading and see you next time!