Skip to content

Commit

Permalink
Flutter com web API: integrando sua app mobile
Browse files Browse the repository at this point in the history
  • Loading branch information
muriloao committed Jul 28, 2020
1 parent 65a4ac1 commit 1f600c9
Show file tree
Hide file tree
Showing 15 changed files with 445 additions and 52 deletions.
2 changes: 1 addition & 1 deletion .flutter-plugins-dependencies
Original file line number Diff line number Diff line change
@@ -1 +1 @@
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"sqflite","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.1.7+2\\\\","dependencies":[]}],"android":[{"name":"sqflite","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.1.7+2\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"sqflite","dependencies":[]}],"date_created":"2020-07-28 09:43:34.384780","version":"1.17.5"}
{"info":"This is a generated file; do not edit or check into version control.","plugins":{"ios":[{"name":"http_interceptor","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\http_interceptor-0.1.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.1.7+2\\\\","dependencies":[]}],"android":[{"name":"http_interceptor","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\http_interceptor-0.1.1\\\\","dependencies":[]},{"name":"sqflite","path":"C:\\\\flutter\\\\.pub-cache\\\\hosted\\\\pub.dartlang.org\\\\sqflite-1.1.7+2\\\\","dependencies":[]}],"macos":[],"linux":[],"windows":[],"web":[]},"dependencyGraph":[{"name":"http_interceptor","dependencies":[]},{"name":"sqflite","dependencies":[]}],"date_created":"2020-07-28 09:47:41.675852","version":"1.17.5"}
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@
A new Flutter project.

Study application
Held in the course [Persistência com Flutter: Crie um app com armazenamento interno](https://cursos.alura.com.br/course/flutter-persistencia-interna)
Held in the course [Flutter com web API: integrando sua app mobile](https://cursos.alura.com.br/course/flutter-web-api)
41 changes: 41 additions & 0 deletions lib/components/centered_message.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
import 'package:flutter/material.dart';

class CenteredMessage extends StatelessWidget {
final String message;
final IconData icon;
final double iconSize;
final double fontSize;

CenteredMessage(
this.message, {
this.icon,
this.iconSize = 64,
this.fontSize = 24,
});

@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
Visibility(
child: Icon(
icon,
size: iconSize,
),
visible: icon != null,
),
Padding(
padding: const EdgeInsets.only(top: 24.0),
child: Text(
message,
style: TextStyle(fontSize: fontSize),
),
),
],
),
);
}
}
22 changes: 22 additions & 0 deletions lib/components/progress.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
import 'package:flutter/material.dart';

class Progress extends StatelessWidget {

final String message;

Progress({this.message = 'Loading'});

@override
Widget build(BuildContext context) {
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text(message)
],
),
);
}
}
21 changes: 21 additions & 0 deletions lib/http/interceptors/logging_interceptor.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import 'package:http_interceptor/http_interceptor.dart';

class LoggingInterceptor implements InterceptorContract {
@override
Future<RequestData> interceptRequest({RequestData data}) async {
print('Request');
print('url: ${data.requestUrl}');
print('headers: ${data.headers}');
print('body: ${data.body}');
return data;
}

@override
Future<ResponseData> interceptResponse({ResponseData data}) async {
print('Response');
print('status code: ${data.statusCode}');
print('headers: ${data.headers}');
print('body: ${data.body}');
return data;
}
}
12 changes: 12 additions & 0 deletions lib/http/webclient.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
import 'package:http/http.dart';
import 'package:http_interceptor/http_interceptor.dart';

import 'interceptors/logging_interceptor.dart';

final Client client = HttpClientWithInterceptor.build(
interceptors: [LoggingInterceptor()],
);

const String baseUrl = 'http://192.168.20.249:8080/transactions';


30 changes: 30 additions & 0 deletions lib/http/webclients/transaction_webclient.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import 'dart:convert';

import 'package:bytebank/http/webclient.dart';
import 'package:bytebank/models/transaction.dart';
import 'package:http/http.dart';

class TransactionWebClient {
Future<List<Transaction>> findAll() async {
final Response response =
await client.get(baseUrl).timeout(Duration(seconds: 5));
final List<dynamic> decodedJson = jsonDecode(response.body);
return decodedJson
.map((dynamic json) => Transaction.fromJson(json))
.toList();
}

Future<Transaction> save(Transaction transaction) async {
final String transactionJson = jsonEncode(transaction.toJson());

final Response response = await client.post(baseUrl,
headers: {
'Content-type': 'application/json',
'password': '1000',
},
body: transactionJson);

return Transaction.fromJson(jsonDecode(response.body));
}

}
11 changes: 11 additions & 0 deletions lib/models/contact.dart
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,15 @@ class Contact {
String toString() {
return 'Contact{id: $id, name: $name, accountNumber: $accountNumber}';
}

Contact.fromJson(Map<String, dynamic> json)
: id = json['id'],
name = json['name'],
accountNumber = json['accountNumber'];

Map<String, dynamic> toJson() =>
{
'name': name,
'accountNumber': accountNumber,
};
}
27 changes: 27 additions & 0 deletions lib/models/transaction.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import 'contact.dart';

class Transaction {
final double value;
final Contact contact;

Transaction(
this.value,
this.contact,
);

Transaction.fromJson(Map<String, dynamic> json) :
value = json['value'],
contact = Contact.fromJson(json['contact']);

Map<String, dynamic> toJson() =>
{
'value': value,
'contact': contact.toJson(),
};

@override
String toString() {
return 'Transaction{value: $value, contact: $contact}';
}

}
34 changes: 20 additions & 14 deletions lib/screens/contacts_list.dart
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import 'package:bytebank/components/progress.dart';
import 'package:bytebank/database/dao/contact_dao.dart';
import 'package:bytebank/models/contact.dart';
import 'package:bytebank/screens/contact_form.dart';
import 'package:bytebank/screens/transaction_form.dart';
import 'package:flutter/material.dart';

class ContactsList extends StatelessWidget {

final ContactDao _dao = ContactDao();

@override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text('Contacts'),
title: Text('Transfer'),
),
body: FutureBuilder<List<Contact>>(
initialData: List(),
Expand All @@ -21,16 +22,7 @@ class ContactsList extends StatelessWidget {
case ConnectionState.none:
break;
case ConnectionState.waiting:
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: <Widget>[
CircularProgressIndicator(),
Text('Loading')
],
),
);
return Progress();
break;
case ConnectionState.active:
break;
Expand All @@ -39,7 +31,16 @@ class ContactsList extends StatelessWidget {
return ListView.builder(
itemBuilder: (context, index) {
final Contact contact = contacts[index];
return _ContactItem(contact);
return _ContactItem(
contact,
onClick: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TransactionForm(contact),
),
);
},
);
},
itemCount: contacts.length,
);
Expand All @@ -66,13 +67,18 @@ class ContactsList extends StatelessWidget {

class _ContactItem extends StatelessWidget {
final Contact contact;
final Function onClick;

_ContactItem(this.contact);
_ContactItem(
this.contact, {
@required this.onClick,
});

@override
Widget build(BuildContext context) {
return Card(
child: ListTile(
onTap: () => onClick(),
title: Text(
contact.name,
style: TextStyle(
Expand Down
116 changes: 80 additions & 36 deletions lib/screens/dashboard.dart
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import 'package:bytebank/screens/contacts_list.dart';
import 'package:bytebank/screens/transactions_list.dart';
import 'package:flutter/material.dart';

class Dashboard extends StatelessWidget {
Expand All @@ -16,46 +17,89 @@ class Dashboard extends StatelessWidget {
padding: const EdgeInsets.all(8.0),
child: Image.asset('images/bytebank_logo.png'),
),
Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
color: Theme.of(context).primaryColor,
child: InkWell(
onTap: () {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ContactsList(),
),
);
},
child: Container(
padding: EdgeInsets.all(8.0),
height: 100,
width: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(
Icons.people,
color: Colors.white,
size: 24.0,
),
Text(
'Contacts',
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
)
],
),
Container(
height: 120,
child: ListView(
scrollDirection: Axis.horizontal,
children: <Widget>[
_FeatureItem(
'Transfer',
Icons.monetization_on,
onClick: () => _showContactsList(context),
),
_FeatureItem(
'Transaction Feed',
Icons.description,
onClick: () => _showTransactionsList(context),
),
),
],
),
)
),
],
),
);
}

void _showContactsList(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => ContactsList(),
),
);
}

_showTransactionsList(BuildContext context) {
Navigator.of(context).push(
MaterialPageRoute(
builder: (context) => TransactionsList(),
),
);
}
}

class _FeatureItem extends StatelessWidget {
final String name;
final IconData icon;
final Function onClick;

_FeatureItem(
this.name,
this.icon, {
@required this.onClick,
});

@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.all(8.0),
child: Material(
color: Theme.of(context).primaryColor,
child: InkWell(
onTap: () => onClick(),
child: Container(
padding: EdgeInsets.all(8.0),
width: 150,
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.start,
children: <Widget>[
Icon(
icon,
color: Colors.white,
size: 24.0,
),
Text(
name,
style: TextStyle(
color: Colors.white,
fontSize: 16.0,
),
)
],
),
),
),
),
);
}
}
Loading

0 comments on commit 1f600c9

Please sign in to comment.