1import 'dart:async';
2
3import 'package:flutter/material.dart';
4import 'package:parse_server_sdk_flutter/parse_server_sdk_flutter.dart';
5import 'package:image_picker/image_picker.dart';
6import 'package:flutter/foundation.dart';
7import 'dart:io';
8
9void main() async {
10 WidgetsFlutterBinding.ensureInitialized();
11
12 const keyParseApplicationId = 'YOUR_APPLICATION_ID';
13 const keyParseClientKey = 'YOUR_CLIENT_KEY';
14 const keyParseServerUrl = 'https://parseapi.back4app.com';
15 await Parse().initialize(
16 keyParseApplicationId,
17 keyParseServerUrl,
18 clientKey: keyParseClientKey,
19 autoSendSessionId: true,
20 debug: true,
21 );
22
23 runApp(const MyApp());
24}
25
26class MyApp extends StatelessWidget {
27 const MyApp({super.key});
28
29 @override
30 Widget build(BuildContext context) {
31 return MaterialApp(
32 title: 'DataTypes',
33 theme: ThemeData(
34 primarySwatch: Colors.blue,
35 ),
36 home: const MyHomePage(),
37 );
38 }
39}
40
41class MyHomePage extends StatefulWidget {
42 const MyHomePage({super.key});
43
44 @override
45 _MyHomePageState createState() => _MyHomePageState();
46}
47
48class _MyHomePageState extends State<MyHomePage> {
49 final TextEditingController _stringController = TextEditingController();
50 final TextEditingController _doubleController = TextEditingController();
51 final TextEditingController _listStringController = TextEditingController();
52 final TextEditingController _listIntController = TextEditingController();
53 final TextEditingController _pointerController = TextEditingController();
54 final TextEditingController _objectIdController = TextEditingController();
55 final TextEditingController _uniqueValueController = TextEditingController();
56 final TextEditingController _removeValueController = TextEditingController();
57
58 bool _boolValue = false;
59 DateTime _selectedDate = DateTime.now();
60 final String _responseMessage = '';
61 XFile? pickedFile;
62 bool isLoading = false;
63
64 @override
65 Widget build(BuildContext context) {
66 return Scaffold(
67 appBar: AppBar(
68 title: const Text('DataTypes'),
69 ),
70 body: Padding(
71 padding: const EdgeInsets.all(16.0),
72 child: SingleChildScrollView(
73 child: Column(
74 crossAxisAlignment: CrossAxisAlignment.start,
75 children: <Widget>[
76 _buildTextField('String Field', _stringController),
77 const SizedBox(height: 20),
78 _buildTextField('Double Field', _doubleController,
79 isNumeric: true),
80 const SizedBox(height: 20),
81 _buildSwitch('Bool Field', _boolValue, (value) {
82 setState(() {
83 _boolValue = value;
84 });
85 }),
86 const SizedBox(height: 20),
87 TextButton(
88 onPressed: () => _selectDate(context),
89 child: Text(
90 'Select Date: ${_selectedDate.toLocal()}'.split(' ')[0]),
91 ),
92 const SizedBox(height: 20),
93 _buildTextField(
94 'List String Field (comma-separated)', _listStringController),
95 const SizedBox(height: 20),
96 _buildTextField(
97 'List Int Field (comma-separated)', _listIntController),
98 const SizedBox(height: 20),
99 _buildTextField('Pointer Field (Object ID)', _pointerController),
100 const SizedBox(height: 20),
101 _buildImagePicker(),
102 const SizedBox(height: 20),
103 ElevatedButton(
104 onPressed: _saveData,
105 child: const Text('Save'),
106 ),
107 const SizedBox(height: 20),
108 ElevatedButton(
109 onPressed: () async {
110 await _deleteData(_objectIdController.text);
111
112 },
113 child: const Text('Delete'),
114 ),
115 const SizedBox(height: 20),
116 _buildTextField(
117 'Object ID to Delete or Update', _objectIdController),
118 ElevatedButton(
119 onPressed: () async {
120 await _updateData(_objectIdController.text);
121 },
122 child: const Text('Update'),
123 ),
124 const SizedBox(height: 20),
125 _buildIncrementDecrementButtons(),
126 const SizedBox(height: 20),
127 _buildListOperations(),
128 const SizedBox(height: 20),
129 Text(_responseMessage),
130 ],
131 ),
132 ),
133 ),
134 );
135 }
136
137 Widget _buildTextField(String label, TextEditingController controller,
138 {bool isNumeric = false}) {
139 return TextField(
140 controller: controller,
141 keyboardType: isNumeric ? TextInputType.number : TextInputType.text,
142 decoration: InputDecoration(
143 border: const OutlineInputBorder(),
144 labelText: label,
145 ),
146 );
147 }
148
149 Widget _buildSwitch(String label, bool value, Function(bool) onChanged) {
150 return SwitchListTile(
151 title: Text(label),
152 value: value,
153 onChanged: onChanged,
154 );
155 }
156
157 Widget _buildImagePicker() {
158 return GestureDetector(
159 child: pickedFile != null
160 ? Container(
161 width: 250,
162 height: 250,
163 decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
164 child: kIsWeb
165 ? Image.network(pickedFile!.path)
166 : Image.file(File(pickedFile!.path)),
167 )
168 : Container(
169 width: 250,
170 height: 250,
171 decoration: BoxDecoration(border: Border.all(color: Colors.blue)),
172 child: const Center(
173 child: Text('Click here to pick image from GamePoint')),
174 ),
175 onTap: () async {
176 final picker = ImagePicker();
177 XFile? image = (await picker.pickImage(source: ImageSource.gallery));
178 if (image != null) {
179 setState(() {
180 pickedFile = image;
181 });
182 }
183 },
184 );
185 }
186
187 Widget _buildIncrementDecrementButtons() {
188 return Row(
189 mainAxisAlignment: MainAxisAlignment.spaceBetween,
190 children: [
191 Expanded(
192 child: ElevatedButton(
193 onPressed: () async {
194 await _incrementField(_objectIdController.text);
195 },
196 child: const Text('+ Double'),
197 ),
198 ),
199 const SizedBox(width: 10),
200 Expanded(
201 child: ElevatedButton(
202 onPressed: () async {
203 await _decrementField(_objectIdController.text);
204 },
205 child: const Text('- Double'),
206 ),
207 ),
208 ],
209 );
210 }
211
212 Widget _buildListOperations() {
213 return Column(
214 children: [
215 _buildTextField('Unique Value to Add', _uniqueValueController),
216 ElevatedButton(
217 onPressed: () async {
218 await _addUniqueToList(
219 _objectIdController.text, _uniqueValueController.text);
220 },
221 child: const Text('Add Unique'),
222 ),
223 const SizedBox(height: 20),
224 _buildTextField('Value to Remove', _removeValueController),
225 ElevatedButton(
226 onPressed: () async {
227 await _removeFromList(
228 _objectIdController.text, _removeValueController.text);
229 },
230 child: const Text('Remove'),
231 ),
232 ],
233 );
234 }
235
236 Future<void> _saveData() async {
237
238 String stringValue = _stringController.text;
239 List<String> listStringValue = _listStringController.text.isNotEmpty
240 ? _listStringController.text
241 .split(',')
242 .map((e) =>
243 e.trim())
244 .toList()
245 : [];
246 List<int> listtIntValue = _listIntController.text.isNotEmpty
247 ? _listIntController.text
248 .split(',')
249 .map(
250 (e) => int.parse(e.trim()))
251 .toList()
252 : [];
253 double? doubleValue;
254 if (_doubleController.text.isNotEmpty) {
255 doubleValue = double.parse(_doubleController.text);
256 }
257 bool boolValue = _boolValue;
258 DateTime selectedDate = _selectedDate;
259
260 final gamePoint = ParseObject('GamePoint')
261 ..set('bool', boolValue)
262 ..set('date', selectedDate);
263 if (stringValue.isNotEmpty) gamePoint.set('string', stringValue);
264 if (doubleValue != null) gamePoint.set('double', doubleValue);
265 if (listStringValue.isNotEmpty) {
266 gamePoint.setAddAll('listString', listStringValue);
267 }
268 if (listtIntValue.isNotEmpty) gamePoint.setAddAll('listint', listtIntValue);
269 if (_pointerController.text.isNotEmpty) {
270 gamePoint.set('pointer', _parsePointer(_pointerController.text));
271 }
272
273 if (pickedFile != null) {
274 setState(() {
275 isLoading = true;
276 });
277
278 ParseFileBase? parseFile;
279
280 if (kIsWeb) {
281 parseFile =
282 ParseWebFile(await pickedFile!.readAsBytes(), name: 'file.jpg');
283 } else {
284 parseFile = ParseFile(File(pickedFile!.path));
285 }
286 await parseFile.save();
287
288 gamePoint.set('file', parseFile);
289 }
290
291 var apiResponse = await gamePoint.save();
292
293 if (apiResponse.success && apiResponse.results != null) {
294 setState(() {
295 isLoading = false;
296 pickedFile = null;
297 });
298
299 ScaffoldMessenger.of(context)
300 ..removeCurrentSnackBar()
301 ..showSnackBar(const SnackBar(
302 content: Text(
303 'File saved successfully on Back4app',
304 style: TextStyle(color: Colors.white),
305 ),
306 duration: Duration(seconds: 3),
307 backgroundColor: Colors.blue,
308 ));
309 } else {
310 print("This is your request error: ${apiResponse.error}");
311 }
312 }
313
314 Future<void> _updateData(String objectId) async {
315 final gamePoint = ParseObject('GamePoint')..objectId = objectId;
316
317 if (_stringController.text.isNotEmpty) {
318 gamePoint.set('string', _stringController.text);
319 }
320
321 if (_doubleController.text.isNotEmpty) {
322 gamePoint.set('double', double.parse(_doubleController.text));
323 }
324
325 gamePoint.set('bool', _boolValue);
326 gamePoint.set('date', _selectedDate);
327
328 if (_listStringController.text.isNotEmpty) {
329 List<String> listStringValue =
330 _listStringController.text.split(',').map((e) => e.trim()).toList();
331 gamePoint.setAddAll('listString', listStringValue);
332 }
333
334 if (_listIntController.text.isNotEmpty) {
335 List<int> listIntValue = _listIntController.text
336 .split(',')
337 .map((e) => int.parse(e.trim()))
338 .toList();
339 gamePoint.setAddUnique('listint', listIntValue);
340 }
341
342 if (_pointerController.text.isNotEmpty) {
343 gamePoint.set('pointer', _parsePointer(_pointerController.text));
344 }
345
346 if (pickedFile != null) {
347 ParseFileBase? parseFile;
348 if (kIsWeb) {
349 parseFile =
350 ParseWebFile(await pickedFile!.readAsBytes(), name: 'file.jpg');
351 } else {
352 parseFile = ParseFile(File(pickedFile!.path));
353 }
354 await parseFile.save();
355 gamePoint.set('file', parseFile);
356 }
357
358
359 var response = await gamePoint.save();
360
361 if (response.success) {
362 ScaffoldMessenger.of(context).showSnackBar(
363 const SnackBar(content: Text('Data updated successfully!')),
364 );
365 } else {
366 ScaffoldMessenger.of(context).showSnackBar(
367 SnackBar(
368 content: Text('Error updating data: ${response.error!.message}')),
369 );
370 }
371 }
372
373 Future<void> _incrementField(String objectId) async {
374 final gamePoint = ParseObject('GamePoint')
375 ..objectId = objectId
376 ..setIncrement('double', 1);
377 await gamePoint.save();
378 }
379
380 Future<void> _decrementField(String objectId) async {
381 final gamePoint = ParseObject('GamePoint')
382 ..objectId = objectId
383 ..setDecrement('double', -1);
384 await gamePoint.save();
385 }
386
387 Future<void> _addUniqueToList(String objectId, String value) async {
388 final gamePoint = ParseObject('GamePoint')
389 ..objectId = objectId
390 ..setAddUnique('listString', value);
391 await gamePoint.save();
392 }
393
394 Future<void> _removeFromList(String objectId, String value) async {
395 final gamePoint = ParseObject('GamePoint')
396 ..objectId = objectId
397 ..setRemove('listString', value);
398 await gamePoint.save();
399 }
400
401 Future<void> _selectDate(BuildContext context) async {
402 final DateTime? picked = await showDatePicker(
403 context: context,
404 initialDate: _selectedDate,
405 firstDate: DateTime(2000),
406 lastDate: DateTime(2101),
407 );
408 if (picked != null && picked != _selectedDate) {
409 setState(() {
410 _selectedDate = picked;
411 });
412 }
413 }
414
415 Future<void> _deleteData(String objectId) async {
416
417 final parseObject = ParseObject('GamePoint')
418 ..objectId = objectId
419 ..unset("listString");
420
421 await parseObject.save();
422 }
423
424
425 ParseObject _parsePointer(String objectId) {
426
427 final pointer = ParseObject('Game')..objectId = objectId;
428 return pointer;
429 }
430}