Skip to content

Commit 169cd0b

Browse files
trying to wire up sqlite caching
1 parent 20ac288 commit 169cd0b

File tree

15 files changed

+275
-87
lines changed

15 files changed

+275
-87
lines changed

README.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,13 @@
22

33
This app is used to test the following features:
44
- Google Sing In at startup;
5-
- ```Provider Test``` - basic testing of ChangeNotifier class;
5+
- ```Simple Provider Test``` - basic testing of ChangeNotifier class;
66
- ```Future Firestore``` - Fetching data from Firestore. Fetched data is cached into SQLite database;
77
- ```Stream Firestore``` - Streaming data from Firestore. Just showing how you can add, update and delete Firestore data in real time;
88
- ```Clean DB``` - removes all tables from SQLite database and creates them again;
99
- ```Old Json Caching Example``` - fetching data from REST API and caching into SQLite;
1010

1111
- Firebase notifications are also enabled. FCM token is shown in debug console at startup. Copy the token and go to "Cloud messaging" in Firebase console to test it out.
1212

13+
- Provider is listening on Firestore collection changes; Changes can be seen on the Home Page and on "Simple provider test" page;
14+

lib/backend/api.dart

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ class ApiProvider {
1616

1717
Future getDataForFirestore() async {
1818
return readCache().then((value) async {
19+
1920
if (value.isNotEmpty) {
2021
print('READING FROM DB, NUMBER OF ENTRIES: ${value.length}');
2122
callFirestore();
@@ -36,7 +37,7 @@ class ApiProvider {
3637
var array = data.docs.map((e) {
3738
return {'name': e['name']};
3839
}).toList();
39-
await addBatchOfFirestore(list: array);
40+
// await insertSQLite(list: array);
4041
return array;
4142
}
4243

@@ -73,3 +74,5 @@ class ApiProvider {
7374
}
7475
}
7576
}
77+
78+

lib/backend/backend.dart

Whitespace-only changes.

lib/backend/database.dart

Lines changed: 21 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ Future<Database> cacheDatabase() async {
1515
Future<List<Map>> readCache() async {
1616
final db = await cacheDatabase();
1717
var cache = db.query('cache');
18+
cache.then((value) {
19+
print(value);
20+
});
1821

1922
return cache;
2023
}
@@ -26,13 +29,24 @@ Future<List<Map>> readJsonCache() async {
2629
return cache;
2730
}
2831

29-
Future addBatchOfFirestore({required List<Map<String, dynamic>> list}) async {
32+
Future insertSQLite({required Map<String, dynamic> item}) async {
3033
final db = await cacheDatabase();
31-
final batch = db.batch();
32-
for (var item in list) {
33-
batch.insert('cache', item, conflictAlgorithm: ConflictAlgorithm.replace);
34-
}
35-
await batch.commit(noResult: true);
34+
db.insert('cache', item);
35+
// final batch = db.batch();
36+
// for (var item in list) {
37+
// batch.insert('cache', item, conflictAlgorithm: ConflictAlgorithm.replace);
38+
// }
39+
// await batch.commit(noResult: true);
40+
}
41+
42+
Future updateSQLite({required Map<String, dynamic> item}) async {
43+
final db = await cacheDatabase();
44+
db.update('cache', item, where: 'doc_id = ?', whereArgs: [item['doc_id']]);
45+
// final batch = db.batch();
46+
// for (var item in list) {
47+
// batch.insert('cache', item, conflictAlgorithm: ConflictAlgorithm.replace);
48+
// }
49+
// await batch.commit(noResult: true);
3650
}
3751

3852
// add entry
@@ -58,4 +72,5 @@ Future cleanDB() async {
5872
db.execute(Queries().dropJsonTable);
5973
db.execute(Queries().createCacheTable);
6074
db.execute(Queries().jsonCache);
75+
// readCache();
6176
}

lib/backend/firestore_changes.dart

Lines changed: 33 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,54 @@
11
import 'package:cloud_firestore/cloud_firestore.dart';
2+
import 'package:connectivity/connectivity.dart';
3+
import 'package:fetchingapp/backend/database.dart';
24
import 'package:flutter/foundation.dart';
35

46
class FirestoreChanges extends ChangeNotifier {
57
String changeStr = '';
8+
// List<Map<String, dynamic>> list = [];
9+
Map<String, dynamic> map = {};
610

711
void listenOnFirestoreChanges() {
12+
cleanDB();
13+
// _checkInternetConnectivity();
14+
815
FirebaseFirestore.instance
916
.collection('flutter-caching')
1017
.snapshots()
1118
.listen((event) {
19+
print('CHANGE!');
1220
changeStr = '';
21+
// list = [];
1322
for (var change in event.docChanges) {
14-
// print('Change type: ${change.type}; Data: '
15-
// '${change.doc.data()}\n');
23+
map = {'name': change.doc.data()!['name'], 'doc_id': change.doc.id};
24+
if (change.type == DocumentChangeType.added) {
25+
insertSQLite(item: map);
26+
} else if (change.type == DocumentChangeType.modified) {
27+
updateSQLite(item: map);
28+
print('cached modified');
29+
}
30+
31+
// list.add(map);
32+
print('Change type: ${change.type};\n'
33+
'Doc ID: ${change.doc.id}\n'
34+
'Data: ${change.doc.data()}\n\n');
1635
changeStr = changeStr +
1736
'Change type: ${change.type};\n'
1837
'Doc ID: ${change.doc.id}\n'
19-
'Data: ${change.doc.data()}\n';
38+
'Data: ${change.doc.data()}\n\n';
2039
}
2140
notifyListeners();
22-
// changeStr = '';
41+
// addToSQLite(list: list);
42+
// print(list);
2343
});
2444
}
2545
}
46+
47+
// Future<void> _checkInternetConnectivity() async {
48+
// var result = await Connectivity().checkConnectivity();
49+
// if (result != ConnectivityResult.none) {
50+
// cleanDB();
51+
// print('none');
52+
// // return 'none';
53+
// }
54+
// }

lib/backend/sql_queries.dart

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@ class Queries {
44
String createCacheTable = '''
55
CREATE TABLE IF NOT EXISTS cache (
66
id INTEGER PRIMARY KEY,
7-
name TEXT
7+
name TEXT,
8+
doc_id TEXT
89
);
910
''';
1011

lib/main.dart

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,6 @@ import 'package:fetchingapp/backend/firestore_changes.dart';
22
import 'package:fetchingapp/backend/notifications.dart';
33
import 'package:fetchingapp/screens/home.dart';
44
import 'package:fetchingapp/screens/login.dart';
5-
import 'package:fetchingapp/screens/provider_test.dart';
65
import 'package:firebase_auth/firebase_auth.dart';
76
import 'package:flutter/material.dart';
87
import 'package:firebase_core/firebase_core.dart';
@@ -20,7 +19,7 @@ Future<void> main() async {
2019
print('FCM token: $token');
2120

2221
runApp(ChangeNotifierProvider(
23-
create: (_) => Favorites(),
22+
create: (_) => FirestoreChanges(),
2423
child: const MyApp(),
2524
));
2625
}
@@ -51,16 +50,14 @@ class _MyAppState extends State<MyApp> {
5150
firstScreen = const LoginPage();
5251
}
5352

54-
53+
Provider.of<FirestoreChanges>(context, listen: false)
54+
.listenOnFirestoreChanges();
5555

56-
return ChangeNotifierProvider(
57-
create: (_) => FirestoreChanges(),
58-
child: MaterialApp(
59-
theme: ThemeData(
60-
primarySwatch: Colors.blue,
61-
),
62-
home: firstScreen,
56+
return MaterialApp(
57+
theme: ThemeData(
58+
primarySwatch: Colors.blue,
6359
),
60+
home: firstScreen,
6461
);
6562
}
6663
}
Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,66 @@
1+
import 'package:cloud_firestore/cloud_firestore.dart';
2+
import 'package:fetchingapp/backend/database.dart';
3+
import 'package:flutter/material.dart';
4+
5+
class FirestoreCollectionCaching extends StatefulWidget {
6+
const FirestoreCollectionCaching({Key? key}) : super(key: key);
7+
8+
@override
9+
_FirestoreCollectionCachingState createState() =>
10+
_FirestoreCollectionCachingState();
11+
}
12+
13+
class _FirestoreCollectionCachingState
14+
extends State<FirestoreCollectionCaching> {
15+
@override
16+
Widget build(BuildContext context) {
17+
readCache();
18+
cleanDB();
19+
20+
return Scaffold(
21+
appBar: AppBar(
22+
title: const Text('Firestore Collection'),
23+
),
24+
body: Column(
25+
children: [
26+
Expanded(
27+
child: Text('List'),
28+
),
29+
inputfield(),
30+
],
31+
),
32+
);
33+
}
34+
}
35+
36+
Widget inputfield() {
37+
final textController = TextEditingController();
38+
39+
void addEntry() {
40+
if (textController.text == '') {
41+
return;
42+
}
43+
44+
FirebaseFirestore.instance
45+
.collection('flutter-caching')
46+
.add({'name': textController.text});
47+
textController.clear();
48+
}
49+
50+
return TextField(
51+
controller: textController,
52+
onEditingComplete: () {
53+
addEntry();
54+
},
55+
decoration: InputDecoration(
56+
prefixIcon: const Icon(Icons.add_circle),
57+
labelText: "Input new value and click Save:",
58+
suffixIcon: IconButton(
59+
icon: const Icon(Icons.save),
60+
splashColor: Colors.blue,
61+
tooltip: "Post message",
62+
onPressed: () {
63+
addEntry();
64+
},
65+
)));
66+
}

lib/screens/home.dart

Lines changed: 25 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,9 @@
11
import 'package:fetchingapp/backend/database.dart';
2-
import 'package:fetchingapp/backend/firestore_changes.dart';
32
import 'package:fetchingapp/backend/google_authentication.dart';
4-
import 'package:fetchingapp/screens/firestore_stream.dart';
5-
import 'package:fetchingapp/screens/firestore_future.dart';
6-
import 'package:fetchingapp/screens/json_caching.dart';
3+
import 'package:fetchingapp/screens/firestore_collection.dart';
74
import 'package:fetchingapp/screens/login.dart';
8-
import 'package:fetchingapp/screens/provider_test.dart';
95
import 'package:firebase_auth/firebase_auth.dart';
106
import 'package:flutter/material.dart';
11-
import 'package:provider/provider.dart';
127

138
class HomePage extends StatelessWidget {
149
const HomePage(this.user, {Key? key}) : super(key: key);
@@ -17,77 +12,44 @@ class HomePage extends StatelessWidget {
1712

1813
@override
1914
Widget build(BuildContext context) {
20-
Provider.of<FirestoreChanges>(context, listen: false)
21-
.listenOnFirestoreChanges();
22-
2315
return Scaffold(
2416
appBar: AppBar(
2517
automaticallyImplyLeading: false,
2618
title: const Text('Home Screen'),
2719
),
2820
body: Column(
2921
children: [
30-
const SizedBox(height: 10),
3122
userProfileCard(context: context, user: user),
32-
const SizedBox(height: 10),
33-
testSectionButton(
34-
context: context,
35-
name: 'Simple Provider Test',
36-
widget: const ProviderTestPage()),
37-
const SizedBox(height: 10),
38-
testSectionButton(
39-
context: context,
40-
name: 'Future Firestore',
41-
widget: const FutureFireStore()),
42-
const SizedBox(height: 10),
43-
testSectionButton(
44-
context: context,
45-
name: 'Stream Firestore',
46-
widget: const StreamFireStore()),
47-
const SizedBox(height: 10),
48-
cleanDBbutton(),
49-
const SizedBox(height: 10),
50-
testSectionButton(
51-
context: context,
52-
name: 'Old Json Caching Example',
53-
widget: const JsonPage()),
54-
const SizedBox(height: 10),
23+
const SizedBox(
24+
height: 20,
25+
),
26+
ElevatedButton(
27+
onPressed: () {
28+
Navigator.push(
29+
context,
30+
MaterialPageRoute(
31+
builder: (_) => const FirestoreCollectionCaching()));
32+
},
33+
child: const Text(
34+
'Firestore Collection',
35+
style: TextStyle(fontSize: 25),
36+
)),
37+
ElevatedButton(
38+
onPressed: () {
39+
cleanDB();
40+
},
41+
child: const Text('Clean DB')),
42+
ElevatedButton(
43+
onPressed: () {
44+
readCache();
45+
},
46+
child: const Text('Read Cache'))
5547
],
5648
),
5749
);
5850
}
5951
}
6052

61-
Widget testSectionButton(
62-
{required BuildContext context,
63-
required String name,
64-
required Widget widget}) {
65-
return ElevatedButton(
66-
child: Text(
67-
name,
68-
style: const TextStyle(fontSize: 20),
69-
),
70-
onPressed: () {
71-
Navigator.push(
72-
context,
73-
MaterialPageRoute(builder: (context) => widget),
74-
);
75-
},
76-
);
77-
}
78-
79-
Widget cleanDBbutton() {
80-
return ElevatedButton(
81-
child: const Text(
82-
'Clean DB',
83-
style: TextStyle(fontSize: 20),
84-
),
85-
onPressed: () {
86-
cleanDB();
87-
},
88-
);
89-
}
90-
9153
Widget userProfileCard({required BuildContext context, required User user}) {
9254
return Card(
9355
child: ListTile(
File renamed without changes.

0 commit comments

Comments
 (0)