import 'dart:convert'; import 'dart:io'; import 'package:dde_gesture_manager/constants/sp_keys.dart'; import 'package:dde_gesture_manager/extensions.dart'; import 'package:dde_gesture_manager/models/scheme.dart' as AppScheme; import 'package:dde_gesture_manager/utils/helper.dart'; import 'package:dde_gesture_manager/utils/notificator.dart'; import 'package:dde_gesture_manager_api/apis.dart'; import 'package:dde_gesture_manager_api/models.dart'; import 'package:http/http.dart' as http; typedef T BeanBuilder(Map res); typedef T HandleRespBuild(http.Response resp); typedef int GetStatusCodeFunc(Map resp); int getStatusCodeFunc(Map resp) => resp["statusCode"] as int; BeanBuilder> listRespBuilderWrap(BeanBuilder builder) => (Map resp) => (resp['list'] as List).map((e) => builder(e)).toList(); class HttpErrorCode extends Error { int statusCode; HttpErrorCode(this.statusCode, {this.message}); String? message; @override String toString() => '[$statusCode] $message'; } class Api { static _handleHttpError(e) { if (e is SocketException) { Notificator.error( H().topContext, title: LocaleKeys.info_server_error_title.tr(), description: LocaleKeys.info_server_error_description.tr(), ); } else { throw e; } } static HandleRespBuild _handleRespBuild(BeanBuilder builder) => (http.Response resp) { if (builder is GetStatusCodeFunc) return builder({"statusCode": resp.statusCode}); T res; try { var decodeBody = json.decode(utf8.decode(resp.bodyBytes)); res = decodeBody is Map ? builder(decodeBody) : builder({'list': decodeBody}); } catch (e) { e.sout(); throw HttpErrorCode(resp.statusCode, message: resp.body); } return res; }; static Future _get( String path, BeanBuilder builder, { Map? queryParams, bool ignoreToken = false, bool ignoreErrorHandle = false, }) => http .get( Uri( scheme: Apis.apiScheme, host: Apis.apiHost, port: Apis.apiPort, queryParameters: queryParams, path: path, ), headers: { HttpHeaders.contentTypeHeader: ContentType.json.toString(), }..addAll( ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}), ) .then( _handleRespBuild(builder), onError: (e) { if (ignoreErrorHandle) throw e; else return _handleHttpError(e); }, ); static Future _post( String path, BeanBuilder builder, { Map? body, bool ignoreToken = false, bool ignoreErrorHandle = false, }) => http .post( Uri( scheme: Apis.apiScheme, host: Apis.apiHost, port: Apis.apiPort, path: path, ), body: jsonEncode(body), headers: { HttpHeaders.contentTypeHeader: ContentType.json.toString(), }..addAll( ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}), ) .then( _handleRespBuild(builder), onError: (e) { if (ignoreErrorHandle) throw e; else return _handleHttpError(e); }, ); static Future loginOrSignup({ required String email, required String password, }) => _post( Apis.auth.loginOrSignup, LoginSuccessSerializer.fromMap, body: { UserFields.email: email, UserFields.password: password, }, ignoreToken: true, ); static Future checkAppVersion({ignoreErrorHandle = false}) => _get( Apis.system.appVersion, AppVersionSerializer.fromMap, ignoreToken: true, ignoreErrorHandle: ignoreErrorHandle, ); static Future checkAuthStatus() => _get(Apis.auth.status, getStatusCodeFunc, ignoreErrorHandle: true) .then((value) => value == HttpStatus.noContent); static Future uploadScheme({required AppScheme.Scheme scheme, required bool share}) => _post( Apis.scheme.upload, getStatusCodeFunc, body: SchemeSerializer.toMap( Scheme( name: scheme.name, uuid: scheme.id, description: scheme.description, gestures: scheme.gestures, shared: share, ), ), ).then((value) => value == HttpStatus.noContent); static Future> userUploads() => _get(Apis.scheme.userUploads, listRespBuilderWrap(SchemeSerializer.fromMap)); }