Skip to content

Commit 0f8bcce

Browse files
WahdanZphillwiggins
authored andcommitted
make parse shared preferences default store (parse-community#168)
* add decion page to detect parse server availability throw execption if server url is empty navigate to correct page base on current user state * working on example throw exception if sever url is empty add decision page to check availability of parse server navigate to screen base on current user state * create example flow for login and # display list of diet plan items and allow to remove and update it's status * add shared preferences corestore fix bug when create custom corestore implementation * use shared shared preferences in example * make parse shared preferences default store * Update application_constants.dart
1 parent 665b774 commit 0f8bcce

13 files changed

+600
-73
lines changed

README.md

+7
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,14 @@ Parse().initialize(
2525
ApplicationConstants.keyApplicationId,
2626
ApplicationConstants.keyParseServerUrl);
2727
```
28+
if you want to use secure storage also that's allow using sdk on desktop application
29+
```dart
2830
31+
Parse().initialize(keyParseApplicationId, keyParseServerUrl,
32+
masterKey: keyParseMasterKey,
33+
debug: true,
34+
coreStore: CoreStoreImp.getInstance());
35+
```
2936
It's possible to add other params, such as ...
3037

3138
```dart

example/assets/parse.png

123 KB
Loading

example/lib/data/model/diet_plan.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ class DietPlan extends ParseObject implements ParseCloneable {
3232
num get fat => get<num>(keyFat);
3333
set fat(num fat) => set<num>(keyFat, fat);
3434

35-
int get status => get<int>(keyStatus);
36-
set status(int status) => set<int>(keyStatus, status);
35+
bool get status => get<bool>(keyStatus);
36+
set status(bool status) => set<bool>(keyStatus, status);
3737
}

example/lib/main.dart

+27-25
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import 'package:flutter_plugin_example/data/repositories/diet_plan/repository_di
1010
import 'package:flutter_plugin_example/data/repositories/user/repository_user.dart';
1111
import 'package:flutter_plugin_example/domain/constants/application_constants.dart';
1212
import 'package:flutter_plugin_example/domain/utils/db_utils.dart';
13+
import 'package:flutter_plugin_example/pages/decision_page.dart';
1314
import 'package:flutter_stetho/flutter_stetho.dart';
1415
import 'package:parse_server_sdk/parse_server_sdk.dart';
1516

@@ -40,26 +41,21 @@ class MyApp extends StatefulWidget {
4041
class _MyAppState extends State<MyApp> {
4142
DietPlanRepository dietPlanRepo;
4243
UserRepository userRepo;
43-
String text = "";
44-
4544
@override
4645
void initState() {
4746
super.initState();
48-
initData();
47+
// initData();
4948
}
5049

5150
@override
5251
Widget build(BuildContext context) {
5352
return MaterialApp(
54-
home: Scaffold(
55-
appBar: AppBar(
56-
title: const Text('Plugin example app'),
57-
),
58-
body: Center(
59-
child: Text(text),
53+
debugShowCheckedModeBanner: false,
54+
theme: ThemeData(
55+
primarySwatch: Colors.blue,
6056
),
61-
),
62-
);
57+
title: 'Parse Server Example',
58+
home: DecisionPage());
6359
}
6460

6561
Future<void> initData() async {
@@ -70,14 +66,20 @@ class _MyAppState extends State<MyApp> {
7066
Parse().initialize(keyParseApplicationId, keyParseServerUrl,
7167
masterKey: keyParseMasterKey, debug: true);
7268

69+
//parse serve with secure store and desktop support
70+
71+
// Parse().initialize(keyParseApplicationId, keyParseServerUrl,
72+
// masterKey: keyParseMasterKey,
73+
// debug: true,
74+
// coreStore: CoreStoreImp.getInstance());
75+
7376
// Check server is healthy and live - Debug is on in this instance so check logs for result
7477
final ParseResponse response = await Parse().healthCheck();
7578

7679
if (response.success) {
7780
await runTestQueries();
78-
text += 'runTestQueries\n';
81+
print('runTestQueries');
7982
} else {
80-
text += 'Server health check failed';
8183
print('Server health check failed');
8284
}
8385
}
@@ -96,9 +98,9 @@ class _MyAppState extends State<MyApp> {
9698
// getConfigs();
9799
// query();
98100
// initUser();
99-
var instalattion = await ParseInstallation.currentInstallation();
100-
var rees = instalattion.create();
101-
print(rees);
101+
// var instalattion = await ParseInstallation.currentInstallation();
102+
// var rees = instalattion.create();
103+
// print(rees);
102104
//function();
103105
//functionWithParameters();
104106
// test();
@@ -357,13 +359,13 @@ class _MyAppState extends State<MyApp> {
357359
dietPlanRepo ??= DietPlanRepository.init(await getDB());
358360
userRepo ??= UserRepository.init(await getDB());
359361
}
360-
}
361362

362-
const String dietPlansToAdd =
363-
'[{"className":"Diet_Plans","Name":"Textbook","Description":"For an active lifestyle and a straight forward macro plan, we suggest this plan.","Fat":25,"Carbs":50,"Protein":25,"Status":0},'
364-
'{"className":"Diet_Plans","Name":"Body Builder","Description":"Default Body Builders Diet","Fat":20,"Carbs":40,"Protein":40,"Status":0},'
365-
'{"className":"Diet_Plans","Name":"Zone Diet","Description":"Popular with CrossFit users. Zone Diet targets similar macros.","Fat":30,"Carbs":40,"Protein":30,"Status":0},'
366-
'{"className":"Diet_Plans","Name":"Low Fat","Description":"Low fat diet.","Fat":15,"Carbs":60,"Protein":25,"Status":0},'
367-
'{"className":"Diet_Plans","Name":"Low Carb","Description":"Low Carb diet, main focus on quality fats and protein.","Fat":35,"Carbs":25,"Protein":40,"Status":0},'
368-
'{"className":"Diet_Plans","Name":"Paleo","Description":"Paleo diet.","Fat":60,"Carbs":25,"Protein":10,"Status":0},'
369-
'{"className":"Diet_Plans","Name":"Ketogenic","Description":"High quality fats, low carbs.","Fat":65,"Carbs":5,"Protein":30,"Status":0}]';
363+
String dietPlansToAdd =
364+
'[{"className":"Diet_Plans","Name":"Textbook","Description":"For an active lifestyle and a straight forward macro plan, we suggest this plan.","Fat":25,"Carbs":50,"Protein":25,"Status":0},'
365+
'{"className":"Diet_Plans","Name":"Body Builder","Description":"Default Body Builders Diet","Fat":20,"Carbs":40,"Protein":40,"Status":0},'
366+
'{"className":"Diet_Plans","Name":"Zone Diet","Description":"Popular with CrossFit users. Zone Diet targets similar macros.","Fat":30,"Carbs":40,"Protein":30,"Status":0},'
367+
'{"className":"Diet_Plans","Name":"Low Fat","Description":"Low fat diet.","Fat":15,"Carbs":60,"Protein":25,"Status":0},'
368+
'{"className":"Diet_Plans","Name":"Low Carb","Description":"Low Carb diet, main focus on quality fats and protein.","Fat":35,"Carbs":25,"Protein":40,"Status":0},'
369+
'{"className":"Diet_Plans","Name":"Paleo","Description":"Paleo diet.","Fat":60,"Carbs":25,"Protein":10,"Status":0},'
370+
'{"className":"Diet_Plans","Name":"Ketogenic","Description":"High quality fats, low carbs.","Fat":65,"Carbs":5,"Protein":30,"Status":0}]';
371+
}

example/lib/pages/decision_page.dart

+97
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
import 'package:flutter/material.dart';
2+
import 'package:flutter_plugin_example/data/repositories/diet_plan/provider_api_diet_plan.dart';
3+
import 'package:flutter_plugin_example/domain/constants/application_constants.dart';
4+
import 'package:parse_server_sdk/parse_server_sdk.dart';
5+
6+
import 'home_page.dart';
7+
import 'login_page.dart';
8+
9+
class DecisionPage extends StatefulWidget {
10+
@override
11+
_DecisionPageState createState() => _DecisionPageState();
12+
}
13+
14+
class _DecisionPageState extends State<DecisionPage> {
15+
String _parseServerState = 'Checking Parse Server...';
16+
17+
@override
18+
void initState() {
19+
super.initState();
20+
WidgetsBinding.instance.addPostFrameCallback((_) {
21+
_initParse();
22+
});
23+
}
24+
25+
@override
26+
Widget build(BuildContext context) {
27+
return Scaffold(
28+
body: Center(
29+
child: Container(
30+
child: Column(
31+
mainAxisAlignment: MainAxisAlignment.center,
32+
crossAxisAlignment: CrossAxisAlignment.center,
33+
children: <Widget>[
34+
_showLogo(),
35+
const SizedBox(
36+
height: 20,
37+
),
38+
Center(
39+
child: Text(_parseServerState),
40+
),
41+
],
42+
),
43+
),
44+
),
45+
);
46+
}
47+
48+
Widget _showLogo() {
49+
return Hero(
50+
tag: 'hero',
51+
child: Padding(
52+
padding: const EdgeInsets.fromLTRB(0.0, 70.0, 0.0, 0.0),
53+
child: CircleAvatar(
54+
backgroundColor: Colors.transparent,
55+
radius: 48.0,
56+
child: Image.asset('assets/parse.png'),
57+
),
58+
),
59+
);
60+
}
61+
62+
Future<void> _initParse() async {
63+
try {
64+
Parse().initialize(keyParseApplicationId, keyParseServerUrl,
65+
masterKey: keyParseMasterKey, debug: true);
66+
final ParseResponse response = await Parse().healthCheck();
67+
if (response.success) {
68+
final ParseUser user = await ParseUser.currentUser();
69+
if (user != null) {
70+
_redirectToPage(context, HomePage(DietPlanProviderApi()));
71+
} else {
72+
_redirectToPage(context, LoginPage());
73+
}
74+
} else {
75+
setState(() {
76+
_parseServerState =
77+
'Parse Server Not avaiable\n due to ${response.error.toString()}';
78+
});
79+
}
80+
} catch (e) {
81+
setState(() {
82+
_parseServerState = e.toString();
83+
});
84+
}
85+
}
86+
87+
Future<void> _redirectToPage(BuildContext context, Widget page) async {
88+
final MaterialPageRoute<bool> newRoute =
89+
MaterialPageRoute<bool>(builder: (BuildContext context) => page);
90+
91+
bool nav = await Navigator.of(context)
92+
.pushAndRemoveUntil<bool>(newRoute, ModalRoute.withName('/'));
93+
if (nav == true) {
94+
_initParse();
95+
}
96+
}
97+
}

example/lib/pages/home_page.dart

+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
import 'dart:convert';
2+
import 'dart:math';
3+
4+
import 'package:flutter/material.dart';
5+
import 'package:flutter_plugin_example/data/base/api_response.dart';
6+
import 'package:flutter_plugin_example/data/model/diet_plan.dart';
7+
import 'package:flutter_plugin_example/data/repositories/diet_plan/contract_provider_diet_plan.dart';
8+
import 'package:parse_server_sdk/parse_server_sdk.dart';
9+
10+
class HomePage extends StatefulWidget {
11+
HomePage(this._dietPlanProvider);
12+
final DietPlanProviderContract _dietPlanProvider;
13+
14+
@override
15+
_HomePageState createState() => _HomePageState();
16+
}
17+
18+
class _HomePageState extends State<HomePage> {
19+
List<DietPlan> randomDietPlans = [];
20+
21+
@override
22+
void initState() {
23+
super.initState();
24+
final List<dynamic> json = const JsonDecoder().convert(dietPlansToAdd);
25+
for (final Map<String, dynamic> element in json) {
26+
final DietPlan dietPlan = DietPlan().fromJson(element);
27+
randomDietPlans.add(dietPlan);
28+
}
29+
}
30+
31+
@override
32+
Widget build(BuildContext context) {
33+
return WillPopScope(
34+
onWillPop: () async => false,
35+
child: Scaffold(
36+
appBar: AppBar(
37+
automaticallyImplyLeading: false,
38+
title: const Text('Parse Server demo'),
39+
actions: <Widget>[
40+
FlatButton(
41+
child: Text('Logout',
42+
style: TextStyle(fontSize: 17.0, color: Colors.white)),
43+
onPressed: () async {
44+
final ParseUser user = await ParseUser.currentUser();
45+
user.logout(deleteLocalUserData: true);
46+
Navigator.pop(context, true);
47+
})
48+
],
49+
),
50+
body: _showDietList(),
51+
floatingActionButton: FloatingActionButton(
52+
onPressed: () async {
53+
DietPlan dietPlan =
54+
randomDietPlans[Random().nextInt(randomDietPlans.length - 1)];
55+
ParseUser user = await ParseUser.currentUser();
56+
dietPlan.set('user', user);
57+
await widget._dietPlanProvider.add(dietPlan);
58+
setState(() {});
59+
},
60+
tooltip: 'Add Diet Plans',
61+
child: const Icon(Icons.add),
62+
)),
63+
);
64+
}
65+
66+
Widget _showDietList() {
67+
return FutureBuilder<ApiResponse>(
68+
future: widget._dietPlanProvider.getAll(),
69+
builder: (BuildContext context, AsyncSnapshot<ApiResponse> snapshot) {
70+
if (snapshot.hasData) {
71+
if (snapshot.data.success) {
72+
if (snapshot.data.results == null ||
73+
snapshot.data.results.isEmpty) {
74+
return Center(
75+
child: const Text('No Data'),
76+
);
77+
}
78+
}
79+
return ListView.builder(
80+
shrinkWrap: true,
81+
itemCount: snapshot.data.results.length,
82+
itemBuilder: (BuildContext context, int index) {
83+
DietPlan dietPlan = snapshot.data.results[index];
84+
String id = dietPlan.objectId;
85+
String name = dietPlan.name;
86+
String description = dietPlan.description;
87+
bool status = dietPlan.status;
88+
return Dismissible(
89+
key: Key(id),
90+
background: Container(color: Colors.red),
91+
onDismissed: (direction) async {
92+
widget._dietPlanProvider.remove(dietPlan);
93+
},
94+
child: ListTile(
95+
title: Text(
96+
name,
97+
style: TextStyle(fontSize: 20.0),
98+
),
99+
subtitle: Text(description),
100+
trailing: IconButton(
101+
icon: status
102+
? const Icon(
103+
Icons.done_outline,
104+
color: Colors.green,
105+
size: 20.0,
106+
)
107+
: const Icon(Icons.done,
108+
color: Colors.grey, size: 20.0),
109+
onPressed: () async {
110+
dietPlan.status = !dietPlan.status;
111+
await dietPlan.save();
112+
setState(() {});
113+
}),
114+
),
115+
);
116+
});
117+
} else {
118+
return Center(
119+
child: const Text('No Data'),
120+
);
121+
}
122+
});
123+
}
124+
125+
String dietPlansToAdd =
126+
'[{"className":"Diet_Plans","Name":"Textbook","Description":"For an active lifestyle and a straight forward macro plan, we suggest this plan.","Fat":25,"Carbs":50,"Protein":25,"Status":false},'
127+
'{"className":"Diet_Plans","Name":"Body Builder","Description":"Default Body Builders Diet","Fat":20,"Carbs":40,"Protein":40,"Status":true},'
128+
'{"className":"Diet_Plans","Name":"Zone Diet","Description":"Popular with CrossFit users. Zone Diet targets similar macros.","Fat":30,"Carbs":40,"Protein":30,"Status":true},'
129+
'{"className":"Diet_Plans","Name":"Low Fat","Description":"Low fat diet.","Fat":15,"Carbs":60,"Protein":25,"Status":false},'
130+
'{"className":"Diet_Plans","Name":"Low Carb","Description":"Low Carb diet, main focus on quality fats and protein.","Fat":35,"Carbs":25,"Protein":40,"Status":true},'
131+
'{"className":"Diet_Plans","Name":"Paleo","Description":"Paleo diet.","Fat":60,"Carbs":25,"Protein":10,"Status":false},'
132+
'{"className":"Diet_Plans","Name":"Ketogenic","Description":"High quality fats, low carbs.","Fat":65,"Carbs":5,"Protein":30,"Status":true}]';
133+
}

0 commit comments

Comments
 (0)