Skip to content

Commit

Permalink
Local database storage
Browse files Browse the repository at this point in the history
  • Loading branch information
MikeFP committed Jan 18, 2021
1 parent 693d1cd commit 14b6b6f
Show file tree
Hide file tree
Showing 12 changed files with 267 additions and 43 deletions.
2 changes: 2 additions & 0 deletions lib/getit.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,11 @@
import 'package:get_it/get_it.dart';

import 'providers/loan_provider.dart';
import 'services/database_service.dart';

final getIt = GetIt.instance;

void setup() {
getIt.registerSingleton<LoanProvider>(LoanProvider());
getIt.registerSingleton<DatabaseService>(DatabaseService());
}
4 changes: 3 additions & 1 deletion lib/model/loan.dart
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
class Loan {
int id;
String description;
double amount;
DateTime date;

Loan({this.description, this.amount});
Loan({this.id, this.description, this.amount, this.date});
}
3 changes: 2 additions & 1 deletion lib/model/person.dart
Original file line number Diff line number Diff line change
@@ -1,10 +1,11 @@
import 'loan.dart';

class Person {
int id;
String name;
List<Loan> loans;

Person({this.name, this.loans}) {
Person({this.id, this.name, this.loans}) {
if (loans == null) loans = [];
}

Expand Down
26 changes: 21 additions & 5 deletions lib/providers/loan_provider.dart
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,31 @@ import '../model/person.dart';
import 'package:flutter/widgets.dart';

class LoanProvider extends ChangeNotifier {
final _loanStream = StreamController<List<Person>>.broadcast();
Stream<List<Person>> get loanStream => _loanStream.stream;
final _loanerStream = StreamController<List<Person>>.broadcast();
final _loanerCreatedStream = StreamController<Person>.broadcast();
final _loanerUpdatedStream = StreamController<Person>.broadcast();
Stream<List<Person>> get loanerStream => _loanerStream.stream;
Stream<Person> get loanerCreatedStream => _loanerCreatedStream.stream;
Stream<Person> get loanerUpdatedStream => _loanerUpdatedStream.stream;

Future<void> getAllLoans() async {
_loanStream.add(await LoanService.getAllLoans());
Future<void> getAllLoaners() async {
var res = await LoanService.getAllLoaners();
_loanerStream.add(res);
}

Future<void> saveLoaner(Person loaner) async {
if (loaner.id == null) {
_loanerCreatedStream.add(await LoanService.createLoaner(loaner));
} else {
await LoanService.saveLoans(loaner);
_loanerUpdatedStream.add(loaner);
}
}

dispose() {
super.dispose();
_loanStream.close();
_loanerStream.close();
_loanerCreatedStream.close();
_loanerUpdatedStream.close();
}
}
31 changes: 31 additions & 0 deletions lib/services/database_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
import 'package:flutter/widgets.dart';
import 'package:path/path.dart';
import 'package:sqflite/sqflite.dart';

class DatabaseService {
DatabaseService() {
Future(() async {
WidgetsFlutterBinding.ensureInitialized();
_database = openDatabase(
join(await getDatabasesPath(), 'cash_loaf_database.db'),
onCreate: (db, version) {
return Future.wait([
db.execute(
"CREATE TABLE person(id INTEGER PRIMARY KEY, name TEXT)",
),
db.execute(
"CREATE TABLE loan(id INTEGER PRIMARY KEY, description TEXT, amount REAL, date TEXT, person_id INTEGER NOT NULL, FOREIGN KEY (person_id) REFERENCES person (id))",
)
]);
},
onOpen: (db) {
return db.execute('DELETE FROM loan; DELETE FROM person;');
},
version: 1
);
});
}

Future<Database> _database;
Future<Database> get database => _database;
}
91 changes: 89 additions & 2 deletions lib/services/loan_service.dart
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
import 'package:cash_loaf/model/loan.dart';
import 'package:cash_loaf/model/person.dart';
import 'package:collection/collection.dart';
import 'package:sqflite/sqflite.dart';

import '../getit.dart';
import 'database_service.dart';

class LoanService {
static var testLoans = [
Expand All @@ -14,7 +19,89 @@ class LoanService {
Loan(amount: 4100, description: 'Empréstimo'),
]),
];
static Future<List<Person>> getAllLoans() async {
return testLoans;
static Future<List<Person>> getAllLoaners() async {
final Database db = await getIt<DatabaseService>().database;

final List<Map<String, dynamic>> maps = await db.rawQuery(
'SELECT person.*, person.id as person_id, loan.*, loan.id as loan_id FROM person JOIN loan ON person.id = loan.person_id');

var groupedMaps = groupBy(maps, (item) => item['person_id']);

return groupedMaps.entries
.map((item) => Person(
id: item.key,
name: item.value.first['name'],
loans: item.value
.map((row) => Loan(
id: row['loan_id'],
description: row['description'],
date: DateTime.parse(row['date']),
amount: row['amount'],
))
.toList(),
))
.toList();
}

static Future<Person> createLoaner(Person loaner) async {
final Database db = await getIt<DatabaseService>().database;

return await db.transaction((txn) async {
loaner.id = await txn.rawInsert('INSERT INTO person(name) VALUES(?)', [loaner.name]);

for (var loan in loaner.loans) {
if (loan.id == null) {
loan.id = await txn.rawInsert(
'INSERT INTO loan(person_id, description, amount, date) VALUES(?,?, ?, ?)',
[
loaner.id,
loan.description,
loan.amount,
loan.date.toIso8601String()
],
);
} else {
await txn.rawUpdate(
'UPDATE loan SET description = ?, amount = ? WHERE id = ?',
[
loan.description,
loan.amount,
loan.id,
],
);
}
}
return loaner;
});
}

static Future<List<Loan>> saveLoans(Person loaner) async {
final Database db = await getIt<DatabaseService>().database;

return await db.transaction((txn) async {
for (var loan in loaner.loans) {
if (loan.id == null) {
loan.id = await txn.rawInsert(
'INSERT INTO loan(person_id, description, amount, date) VALUES(?,?, ?, ?)',
[
loaner.id,
loan.description,
loan.amount,
loan.date.toIso8601String()
],
);
} else {
await txn.rawUpdate(
'UPDATE loan SET description = ?, amount = ? WHERE id = ?',
[
loan.description,
loan.amount,
loan.id,
],
);
}
}
return loaner.loans;
});
}
}
40 changes: 31 additions & 9 deletions lib/views/add_loan_page.dart
Original file line number Diff line number Diff line change
@@ -1,8 +1,11 @@
import 'package:cash_loaf/model/loan.dart';
import 'package:cash_loaf/model/person.dart';
import 'package:cash_loaf/providers/loan_provider.dart';
import 'package:cash_loaf/utils/after_layout_mixin.dart';
import 'package:flutter/material.dart';
import 'package:flutter_masked_text/flutter_masked_text.dart';

import '../getit.dart';
import '../utils/currency.dart';
import 'person_page.dart';

Expand All @@ -16,11 +19,37 @@ class AddLoanPage extends StatefulWidget {
}

class _AddLoanPageState extends State<AddLoanPage> with AfterLayoutMixin {
TextEditingController amountText = MoneyMaskedTextController();
final provider = getIt<LoanProvider>();
var amountText = MoneyMaskedTextController();
var descriptionText = TextEditingController();
var stepper = PageController();
var targetPage = 0;

void _saveLoan() {
var loaner = Person(
id: widget.person.id,
name: widget.person.name,
loans: widget.person.loans
..add(Loan(
amount: amountText.numberValue,
description: descriptionText.text,
date: DateTime.now(),
)),
);
provider.saveLoaner(loaner);
var callback = (Person data) {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(builder: (context) => PersonPage(person: data)),
ModalRoute.withName('/'));
};
if (widget.person.id == null) {
provider.loanerCreatedStream.first.then(callback);
} else {
provider.loanerUpdatedStream.first.then(callback);
}
}

@override
void afterFirstLayout(BuildContext context) {}

Expand Down Expand Up @@ -174,14 +203,7 @@ class _AddLoanPageState extends State<AddLoanPage> with AfterLayoutMixin {
mainAxisAlignment: MainAxisAlignment.end,
children: [
RaisedButton(
onPressed: () {
Navigator.pushAndRemoveUntil(
context,
MaterialPageRoute(
builder: (context) =>
PersonPage(person: widget.person)),
ModalRoute.withName('/'));
},
onPressed: _saveLoan,
child: Text('CONCLUIR'),
color: Colors.yellow[300],
),
Expand Down
75 changes: 56 additions & 19 deletions lib/views/loans_page.dart
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
import 'dart:async';

import 'package:after_layout/after_layout.dart';
import 'package:cash_loaf/model/person.dart';
import 'package:cash_loaf/providers/loan_provider.dart';
Expand All @@ -16,21 +18,47 @@ class LoansPage extends StatefulWidget {
class _LoansPageState extends State<LoansPage> with AfterLayoutMixin {
final provider = getIt<LoanProvider>();
List<Person> loans = [];
List<StreamSubscription<Object>> subs = [];

@override
void initState() {
super.initState();
}

@override
void afterFirstLayout(BuildContext context) {
provider.getAllLoans();
provider.loanStream.listen((loans) {
subs.add(provider.loanerStream.listen((loans) {
this.loans = loans;
if (mounted) {
setState(() {});
}
});
}));
subs.add(provider.loanerCreatedStream.listen((loaner) {
this.loans.add(loaner);
if (mounted) {
setState(() {});
}
}));
subs.add(provider.loanerUpdatedStream.listen((loaner) {
var i = this.loans.indexWhere((item) => item.id == loaner.id);
if (i == -1) {
this.loans[i] = loaner;
}
if (mounted) {
setState(() {});
}
}));
}

void _getLoaners() {
provider.getAllLoaners();
}

@override
void afterFirstLayout(BuildContext context) {
_getLoaners();
}

@override
void dispose() {
super.dispose();
subs.forEach((sub) => sub.cancel());
}

@override
Expand Down Expand Up @@ -86,18 +114,23 @@ class _LoansPageState extends State<LoansPage> with AfterLayoutMixin {
],
),
),
body: Column(
children: [
SizedBox(height: 10),
Expanded(
child: ListView.builder(
body: SingleChildScrollView(
child: Column(
children: [
SizedBox(height: 10),
ListView.builder(
shrinkWrap: true,
itemCount: loans != null ? loans.length : 0,
itemBuilder: (context, i) => ListTile(
onTap: () {
Navigator.push(
context,
MaterialPageRoute(
builder: (context) => PersonPage(person: loans[i])));
context,
MaterialPageRoute(
settings: RouteSettings(name: "/loaner"),
builder: (context) => PersonPage(person: loans[i])),
).then((_) {
_getLoaners();
});
},
contentPadding: EdgeInsets.fromLTRB(24, 0, 24, 0),
title: Text(loans[i].name),
Expand All @@ -108,13 +141,17 @@ class _LoansPageState extends State<LoansPage> with AfterLayoutMixin {
)),
),
),
),
],
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () {
Navigator.push(context,
MaterialPageRoute(builder: (context) => SelectPersonPage()));
Navigator.push(
context,
MaterialPageRoute(builder: (context) => SelectPersonPage()),
).then((_) {
_getLoaners();
});
},
tooltip: 'Novo empréstimo',
child: Icon(Icons.add),
Expand Down
Loading

0 comments on commit 14b6b6f

Please sign in to comment.