Skip to content

Commit 654a282

Browse files
author
wigginsp
committed
Release v1.0.22 - Merged with master, lint clean
2 parents 47167e3 + 97eb06d commit 654a282

File tree

18 files changed

+535
-22
lines changed

18 files changed

+535
-22
lines changed

.travis.yml

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
language: dart
2+
3+
dart:
4+
- stable
5+
- dev
6+
7+
install:
8+
- git clone https://github.com/flutter/flutter.git -b stable --depth 1
9+
- export PATH=./flutter/bin:$PATH
10+
- flutter doctor
11+
12+
script:
13+
- flutter packages get
14+
- flutter test --no-pub test/
15+
16+
cache:
17+
directories:
18+
- "$HOME/.pub-cache"

README.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
![enter image description here](https://upload.wikimedia.org/wikipedia/commons/1/17/Google-flutter-logo.png)
22
![enter image description here](https://i2.wp.com/blog.openshift.com/wp-content/uploads/parse-server-logo-1.png?fit=200%2C200&ssl=1&resize=350%2C200)
33

4+
[![Build Status](https://travis-ci.org/phillwiggins/flutter_parse_sdk.svg?branch=master)](https://travis-ci.org/phillwiggins/flutter_parse_sdk)
5+
46
## Parse For Flutter!
57
Hi, this is a Flutter plugin that allows communication with a Parse Server, (https://parseplatform.org) either hosted on your own server or another, like (http://Back4App.com).
68

@@ -25,7 +27,14 @@ Parse().initialize(
2527
ApplicationConstants.keyApplicationId,
2628
ApplicationConstants.keyParseServerUrl);
2729
```
30+
if you want to use secure storage also that's allow using sdk on desktop application
31+
```dart
2832
33+
Parse().initialize(keyParseApplicationId, keyParseServerUrl,
34+
masterKey: keyParseMasterKey,
35+
debug: true,
36+
coreStore: CoreStoreImp.getInstance());
37+
```
2938
It's possible to add other params, such as ...
3039

3140
```dart

example/assets/parse.png

123 KB
Loading

example/lib/data/model/diet_plan.dart

Lines changed: 2 additions & 2 deletions
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

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,15 +71,23 @@ class _MyAppState extends State<MyApp> {
7171
Parse().initialize(keyParseApplicationId, keyParseServerUrl,
7272
masterKey: keyParseMasterKey, debug: true);
7373

74+
//parse serve with secure store and desktop support
75+
76+
// Parse().initialize(keyParseApplicationId, keyParseServerUrl,
77+
// masterKey: keyParseMasterKey,
78+
// debug: true,
79+
// coreStore: CoreStoreImp.getInstance());
80+
7481
// Check server is healthy and live - Debug is on in this instance so check logs for result
7582
final ParseResponse response = await Parse().healthCheck();
7683

7784
if (response.success) {
7885
await runTestQueries();
7986
text += 'runTestQueries\n';
87+
print(text);
8088
} else {
8189
text += 'Server health check failed';
82-
print('Server health check failed');
90+
print(text);
8391
}
8492
}
8593

example/lib/pages/decision_page.dart

Lines changed: 97 additions & 0 deletions
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+
final 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

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

0 commit comments

Comments
 (0)