birzha_mobile/lib/models/user/userManager.dart

630 lines
21 KiB
Dart

import 'dart:convert';
import 'package:birzha/components/tabview.dart';
import 'package:birzha/models/chatroom/chatroom.dart';
import 'package:birzha/models/products/composableProduct.dart';
import 'package:birzha/models/products/my_product.dart';
import 'package:birzha/models/settings/settingsModel.dart';
import 'package:birzha/services/helpers.dart';
import 'package:birzha/services/imageUpload.dart';
import 'package:birzha/services/modals.dart';
import 'package:birzha/services/requests.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/scheduler.dart';
import 'package:http/http.dart' as http;
import 'package:birzha/models/exceptions/exception.dart';
import 'package:birzha/models/user/user.dart';
import 'package:birzha/core/manager/manager.dart';
import 'package:provider/provider.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:flutter/material.dart';
import 'package:file_picker/file_picker.dart' as picker;
import 'dart:async';
import 'dart:io';
import 'package:async/async.dart';
class AppUserManager extends Manager<User> {
static AppUserManager of(BuildContext context, {bool listen = false}) {
return Provider.of<AppUserManager>(context, listen: listen);
}
AppUserManager(SharedPreferences prefs) : super(User.spawnFromPrefs(prefs));
void checkCode(BuildContext context, String code) {
addTask(
Task(
computation: () async {
try {
var response = await _checkSmsCode(dataSync.token ?? "", code);
var decoded = jsonDecode(response.body);
if (decoded is Map) {
final success = decoded["status"];
final message = decoded['message']?['backendCode'.translation];
if (!success && message != null && message is String) {
throw MessageException(message);
} else if (!success && message is! String) {
throw OtherException();
}
}
SchedulerBinding.instance?.addPostFrameCallback((timeStamp) {
syncAccount(context);
});
return dataSync.copy;
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'sms_verify',
),
);
}
void syncAccount(BuildContext context) {
addTask(
Task(
computation: () async {
try {
var newSample = dataSync.copy;
if (newSample.isRegistered) {
var userAccountResponse = await _getAccountRequest(newSample.token!);
var decoded = jsonDecode(userAccountResponse.body);
if (decoded['me'] != null) newSample.jSON = {...newSample.jSON, ...decoded['me']};
}
return newSample;
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'sync',
),
);
}
void sendSmsCode(BuildContext context, VoidCallback onSuccess) {
addTask(
Task(
computation: () async {
try {
debugPrint('dataSync.token: ${dataSync.token}');
var response = await _sendSmsCode(dataSync.token ?? "");
var decoded = jsonDecode(response.body);
bool success = decoded['result'] == 0 || decoded['result'] == '0';
if (success) {
onSuccess();
return dataSync.copy;
} else {
var message = decoded['message']?['backendCode'.translation];
if (message != null && message is String) {
throw MessageException(message);
} else {
throw OtherException();
}
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'send_sms'),
);
}
void verifyMail(BuildContext context) {
addTask(Task(
computation: () async {
try {
print('backendCode'.translation);
String? message;
var response = await _verifyEmailRequest(dataSync.token ?? "");
var decoded = jsonDecode(response.body);
print(decoded);
if (decoded is String) {
message = decoded;
}
showSnackBar(
context,
content: message ?? 'verificationMailSent'.translation,
backgroundColor: Colors.blue,
textColor: Colors.white,
duration: const Duration(seconds: 10),
);
return dataSync.copy;
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'verify_mail'));
}
void login(BuildContext context, SampleUser user) {
addTask(
Task(
computation: () async {
try {
var response = await _loginRequest(user);
var decoded = jsonDecode(response.body);
if (decoded['user'] == null)
throw AppExceptions.recognizer(decoded);
else {
var newSample = SampleUser(data: {...decoded['user'], 'token': decoded['token']});
if (newSample.isRegistered) {
var userAccountResponse = await _getAccountRequest(newSample.token!);
var decoded = jsonDecode(userAccountResponse.body);
if (decoded['me'] != null) newSample.jSON = {...newSample.jSON, ...decoded['me']};
}
return newSample.castToRealUser();
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'login',
),
);
}
void register(BuildContext context, SampleUser user) {
addTask(Task(
computation: () async {
try {
var response = await _registerRequest(user);
var decoded = jsonDecode(response.body);
if (decoded['user'] == null)
throw AppExceptions.recognizer(decoded);
else {
var newSample = SampleUser(data: {...decoded['user'], 'token': decoded['token']});
if (newSample.isRegistered) {
var userAccountResponse = await _getAccountRequest(newSample.token!);
var decoded = jsonDecode(userAccountResponse.body);
if (decoded['me'] != null) newSample.jSON = {...newSample.jSON, ...decoded['me']};
}
return newSample.castToRealUser();
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'register'));
}
void logout() async {
addTask(Task(
computation: () {
return SynchronousFuture(SampleUser(data: {}));
},
key: 'logout'));
}
void update(BuildContext context, SampleUser user) {
addTask(
Task(
computation: () async {
try {
debugPrint('sample user $user');
var response = await _updateRequest(user, dataSync.token!);
debugPrint('response: $response');
var decoded = jsonDecode(response.body);
debugPrint('decoded: $decoded');
if (decoded['me'] == null)
throw AppExceptions.recognizer(decoded);
else {
var newSample = SampleUser(data: {
...dataSync.jSON,
...decoded['me'],
});
SchedulerBinding.instance?.addPostFrameCallback((timeStamp) {
syncAccount(context);
});
return newSample.castToRealUser();
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'update',
),
);
}
void balanceUp(BuildContext context, String cardType, double amount) {
addTask(
Task(
computation: () async {
try {
var response = await _balanceUpRequest(dataSync.token!, cardType, amount);
var decoded = jsonDecode(response.body);
var status = decoded['formUrl'] != null && decoded['formUrl'] is String;
if (!status)
throw AppExceptions.recognizer(decoded);
else
linkLauncher(decoded['formUrl']);
return dataSync.copy;
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'balanceUp',
),
);
}
void uploadBill(BuildContext context, picker.PlatformFile? file) {
addTask(
Task(
computation: () async {
try {
String? message;
if (file != null) {
debugPrint('file ${file.name}');
message = await uploadImage(
baseUrl(path: kApiPath + '/balance_update'),
dataSync,
file, //fileResult!.files.first,
'bank_file',
{
'type': 'bank',
},
onUploadProgressCallback: (a, b) {
debugPrint('a $a');
debugPrint('b $b');
},
);
}
debugPrint('message $message');
if (message != null) {
showSnackBar(
context,
content: message,
backgroundColor: Colors.blue,
textColor: Colors.white,
duration: const Duration(seconds: 3),
);
}
return dataSync.copy;
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'uploadBill'),
);
}
void buyFromSeller(BuildContext navigatorContext, Vendor vendor, void Function(Chatroom room) onSuccess) {
addTask(Task(
computation: () async {
try {
if (!dataSync.isRegistered) {
Tabnavigator.maybeOf(navigatorContext)?.changePage(2);
return dataSync.copy;
}
await Future.delayed(Duration(seconds: 3));
var response = await _initChatRequest(dataSync.token ?? "", vendor);
var data = jsonDecode(response.body);
var isSuccess = data['data'] != null;
if (isSuccess) {
onSuccess(Chatroom.init(data: {
...data['data'],
'vendor': {...vendor.jSON}
}));
return dataSync.copy;
} else {
throw AppExceptions.recognizer(data);
}
} catch (ex) {
AppExceptions.exceptionHandler(navigatorContext, ex);
throw ex;
}
},
key: 'buy'));
}
void composeStep1(BuildContext context, List<String> sendKeys) {
addTask(Task(
computation: () async {
try {
var composable = ComposableProduct();
await Future.delayed(const Duration(seconds: 3));
var response = await _postCompositionRequest(composable, dataSync.token ?? "", sendKeys);
var decoded = jsonDecode(response.body);
var success = decoded["status_code"] == 200 || decoded["status_code"] == '200';
if (success) {
int? id = decoded['data']?['product']?['id'];
ComposableProduct().saveProgress(id);
return dataSync.copy;
} else {
throw AppExceptions.recognizer(decoded);
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'compose_1'));
}
void composeStep2(BuildContext context, List<String> sendKeys) {
addTask(Task(
computation: () async {
try {
var composable = ComposableProduct();
if ((composable.localImages.isEmpty && composable.primaryKey == null) || (composable.localImages.isEmpty && composable.remoteImages.isEmpty)) {
throw MessageException('selectAtLeastImage'.translation);
}
var response = await _postMoreRequest(composable, dataSync.token ?? "", sendKeys);
var byteArray = await response.stream.toBytes();
var stringBody = utf8.decode(byteArray);
print(stringBody);
var decoded = jsonDecode(stringBody);
var success = decoded["status_code"] == 200 || decoded["status_code"] == '200';
if (success) {
ComposableProduct().jSON.clear();
return dataSync.copy;
} else {
throw AppExceptions.recognizer(decoded);
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'compose_2'));
}
void deletePost(BuildContext context, MyProduct product) {
addTask(Task(
computation: () async {
try {
var response = await _deletePost(product, dataSync.token ?? "");
var decoded = jsonDecode(response.body);
var success = decoded["status_code"] == 200 || decoded["status_code"] == '200';
if (success) {
return dataSync.copy;
} else {
throw AppExceptions.recognizer(decoded);
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'delete_post'));
}
void deleteImage(BuildContext context, ComposableProduct product, RemoteImageModel image, void Function() onSuccess) {
addTask(Task(
computation: () async {
var navContext = Navigator.of(context).context;
try {
var response = await _deleteImage(product, image, dataSync.token ?? "");
print(response.body);
var decoded = jsonDecode(response.body);
var success = decoded["status_code"] == 200 || decoded["status_code"] == '200';
if (success) {
onSuccess();
return dataSync.copy;
} else {
throw AppExceptions.recognizer(decoded);
}
} catch (ex) {
AppExceptions.exceptionHandler(navContext, ex);
throw ex;
}
},
key: 'delete_image'));
}
void publishPost(BuildContext context, MyProduct product) {
addTask(Task(
computation: () async {
try {
var response = await _publish(product, dataSync.token ?? "");
var decoded = jsonDecode(response.body);
var success = decoded["status_code"] == 200 || decoded["status_code"] == '200';
if (success) {
return dataSync.copy;
} else {
throw AppExceptions.recognizer(decoded);
}
} catch (ex) {
AppExceptions.exceptionHandler(context, ex);
throw ex;
}
},
key: 'publish_post'));
}
Map<String, TaskStatus> _statusTable = {};
TaskStatus getStatusByKey(String key) {
return _statusTable[key] ?? TaskStatus.None;
}
@override
Future<void> destroyTask(String taskId) async {
_statusTable.remove(taskId);
return super.destroyTask(taskId);
}
@override
Future<void> valueListener(newValue) async {
super.valueListener(newValue);
var prefs = await SharedPreferences.getInstance();
if (newValue.jSON.isEmpty)
prefs.remove('user');
else
await prefs.setString('user', jsonEncode({...newValue.storingData}));
}
@override
void listenerCallBack(TaskResult<User?> result, String taskKey) {
_statusTable[taskKey] = result.status;
notifyListeners();
}
}
Future<http.Response> _loginRequest(SampleUser user) {
return http.post(
baseUrl(path: 'api' + '/login'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
body: jsonEncode(
{...user.jSON},
),
);
}
Future<http.Response> _registerRequest(SampleUser user) {
return http.post(
baseUrl(path: 'api' + '/signup'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json'},
body: jsonEncode(
{...user.jSON},
),
);
}
Future<http.Response> _updateRequest(SampleUser user, String token) {
return http.post(
baseUrl(path: 'api' + '/me'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode(
{...user.jSON},
),
);
}
Future<http.Response> _postCompositionRequest(ComposableProduct composition, String token, List<String> keys) {
return http.post(
baseUrl(path: kApiPath + '/products'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode(
{...composition.jSON}..removeWhere((key, value) => !keys.contains(key)),
),
);
}
Future<http.Response> _deletePost(MyProduct composition, String token) {
return http.delete(baseUrl(path: kApiPath + '/my-products/${composition.primaryKey}'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'});
}
Future<http.Response> _deleteImage(ComposableProduct product, RemoteImageModel image, String token) {
return http.delete(baseUrl(path: kApiPath + '/products/${product.primaryKey}/image-delete/${image.id}'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'});
}
Future<http.Response> _publish(MyProduct composition, String token) {
return http.post(baseUrl(path: kApiPath + '/products/${composition.primaryKey}/publish'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'});
}
Future<http.StreamedResponse> _postMoreRequest(ComposableProduct composition, String token, List<String> keys) {
var multipart = http.MultipartRequest('POST', baseUrl(path: kApiPath + '/products/${composition.primaryKey}'));
var images = composition.localImages;
var files = <http.MultipartFile>[];
for (var image in images) {
var file = File(image.primaryKey);
var stream = http.ByteStream(DelegatingStream(file.openRead()));
var multipartFile = http.MultipartFile('new_img[]', stream, file.lengthSync(), filename: image.primaryKey.split('/').last);
files.add(multipartFile);
}
if (files.isNotEmpty) {
multipart.files.addAll(files);
}
multipart.fields.addAll({
for (var key in composition.jSON.keys.where((element) => keys.contains(element)).where((element) => element != 'new_img'))
key: composition.jSON[key].toString(),
});
for (var i = 0; i < composition.remoteImages.length; i++) {
multipart.fields['old_img[$i]'] = composition.remoteImages[i].primaryKey;
}
multipart.headers.addAll(
{'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'},
);
return multipart.send();
}
Future<http.Response> _balanceUpRequest(String token, String cardType, double amount) {
return http.post(
baseUrl(path: kApiPath + '/balance_update'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
body: jsonEncode(
{
'type': 'online',
'amount': amount.toString(),
'card_type': cardType,
},
),
);
}
Future<http.Response> _getAccountRequest(String token) {
return http.get(
baseUrl(path: 'api' + '/me'),
headers: {
'Content-Type': 'application/json',
'Accept': 'application/json',
'Authorization': 'Bearer $token',
},
);
}
Future<http.Response> _initChatRequest(String token, Vendor vendor) {
return http.post(
baseUrl(path: kApiPath + '/messages/initialize-chatting/' + vendor.primaryKey.toString()),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'},
);
}
Future<http.Response> _verifyEmailRequest(String token) {
print(jsonEncode({'locale': 'backendCode'.translation}));
return http.post(baseUrl(path: kApiPath + '/send-email-verification-link'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'},
body: jsonEncode({'locale': 'backendCode'.translation}));
}
Future<http.Response> _sendSmsCode(String token) {
return http.post(baseUrl(path: kApiPath + '/send-sms-code'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'});
}
Future<http.Response> _checkSmsCode(String token, String code) {
return http.post(baseUrl(path: kApiPath + '/check-sms-code'),
headers: {'Content-Type': 'application/json', 'Accept': 'application/json', 'Authorization': 'Bearer $token'}, body: jsonEncode({"sms_code": code}));
}