166 lines
7.5 KiB
Dart
166 lines
7.5 KiB
Dart
|
|
import 'dart:io';
|
|
import 'package:dio/dio.dart';
|
|
import 'package:flutter/material.dart';
|
|
import 'package:alert_banner/exports.dart';
|
|
import 'package:localstorage/localstorage.dart';
|
|
import 'package:oc_front/models/abstract.dart';
|
|
import 'package:oc_front/models/response.dart';
|
|
import 'package:oc_front/widgets/dialog/alert.dart';
|
|
import 'package:oc_front/core/services/html.dart' if (kIsWeb) 'dart:html' as http;
|
|
|
|
class APIService<T extends SerializerDeserializer> {
|
|
static bool forceRequest = false;
|
|
static Map<String, APIResponse<dynamic>> cache = <String, APIResponse<dynamic>>{};
|
|
Dio _dio = Dio(
|
|
BaseOptions(
|
|
baseUrl: const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080'), // you can keep this blank
|
|
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
|
),
|
|
)..interceptors.add(LogInterceptor( requestHeader: true, ));
|
|
|
|
APIService({ required String baseURL}) {
|
|
_dio = Dio(
|
|
BaseOptions(
|
|
baseUrl: baseURL, // you can keep this blank
|
|
headers: { 'Content-Type': 'application/json; charset=UTF-8' },
|
|
),
|
|
)..interceptors.add(LogInterceptor( requestHeader: true, ),);
|
|
}
|
|
|
|
Future<APIResponse<T>> call(
|
|
String url, String method, Map<String, dynamic>? body, bool force, BuildContext? context) async {
|
|
switch (method.toLowerCase()) {
|
|
case 'get' : return await get(url, force, context);
|
|
case 'post' : return await post(url, body!, context);
|
|
case 'put' : return await put(url, body!, context);
|
|
case 'delete' : return await delete(url, context);
|
|
default : return await get(url, force, context);
|
|
}
|
|
}
|
|
Future<Response> _request(String url, String method, dynamic body, Options? options) async {
|
|
switch (method.toLowerCase()) {
|
|
case 'get' : return await _dio.get(url, options: options);
|
|
case 'post' : return await _dio.post(url, data:body, options: options);
|
|
case 'put' : return await _dio.put(url, data: body!, options: options);
|
|
case 'delete' : return await _dio.delete(url, options: options);
|
|
default : return await _dio.get(url, options: options);
|
|
}
|
|
}
|
|
ValueNotifier downloadProgressNotifier = ValueNotifier(0);
|
|
Future _mainDownload(String url, String method, bool isFilter, String? extend, String savePath, bool isWeb, BuildContext context) async {
|
|
try {
|
|
downloadProgressNotifier.value = 0;
|
|
if (isWeb) {
|
|
_dio.get("$url${extend ?? ""}").then((value) {
|
|
var url = http.Url.createObjectUrlFromBlob(http.Blob([value.data]));
|
|
http.AnchorElement(href: url)..setAttribute('download', savePath.split("/").last)..click();
|
|
downloadProgressNotifier.value = 100;
|
|
Future.delayed(const Duration(seconds: 1), () { Navigator.of(context).pop(); });
|
|
});
|
|
} else {
|
|
_dio.download("$url${extend ?? ""}", savePath, onReceiveProgress: (actualBytes, int totalBytes) {
|
|
Future.delayed(const Duration(seconds: 1), () {
|
|
downloadProgressNotifier.value = (actualBytes / totalBytes * 100).floor();
|
|
if (downloadProgressNotifier.value == 100) { Navigator.of(context).pop(); }
|
|
});
|
|
});
|
|
}
|
|
|
|
} catch (e) { /* */ }
|
|
}
|
|
|
|
Future<APIResponse<T>> _main(String url, dynamic body, String method, String succeed, bool force,
|
|
BuildContext? context, Options? options) async {
|
|
var err = "";
|
|
try {
|
|
var type = localStorage.getItem('tokenType') ?? "bearer";
|
|
_dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}";
|
|
_dio.interceptors.clear();
|
|
var response = await _request(url, method, body, options);
|
|
if (response.statusCode != null && response.statusCode! < 400) {
|
|
if (method == "delete") { cache.remove(url); return APIResponse<T>(); }
|
|
APIResponse<T> resp = APIResponse<T>().deserialize(response.data);
|
|
if (resp.error == "") {
|
|
if (context != null && succeed != "") {
|
|
// ignore: use_build_context_synchronously
|
|
showAlertBanner(context, () {}, InfoAlertBannerChild(text: succeed), // <-- Put any widget here you want!
|
|
alertBannerLocation: AlertBannerLocation.bottom,);
|
|
}
|
|
return resp;
|
|
}
|
|
err = resp.error ?? "internal error";
|
|
}
|
|
if (response.statusCode == 401) { err = "not authorized"; }
|
|
} catch(e, s) {
|
|
print(e);
|
|
print(s);
|
|
err = e.toString();
|
|
}
|
|
//if (err.contains("token") && err.contains("expired")) { AuthService().unAuthenticate(); }
|
|
if (context != null) {
|
|
// ignore: use_build_context_synchronously
|
|
showAlertBanner( context, () {}, AlertAlertBannerChild(text: err),// <-- Put any widget here you want!
|
|
alertBannerLocation: AlertBannerLocation.bottom,);
|
|
}
|
|
throw Exception(err);
|
|
}
|
|
|
|
Future<APIResponse<RawData>> raw(String url, dynamic body, String method) async {
|
|
var err = "";
|
|
if (url != "") {
|
|
try {
|
|
var type = localStorage.getItem('tokenType') ?? "bearer";
|
|
_dio.options.headers["Authorization"] = "${type[0].toUpperCase() + type.substring(1)} ${localStorage.getItem('accessToken') ?? ""}";
|
|
_dio.interceptors.clear();
|
|
var response = await _request(url, method, body, null);
|
|
if (response.statusCode != null && response.statusCode! < 400) {
|
|
if (method == "delete") { cache.remove(url); return APIResponse<RawData>(); }
|
|
APIResponse<RawData> resp = APIResponse<RawData>().deserialize(response.data);
|
|
if (resp.error == "") { return resp; }
|
|
err = resp.error ?? "internal error";
|
|
}
|
|
if (response.statusCode == 401) { err = "not authorized"; }
|
|
} catch(e, s) { print(e); print(s);
|
|
err = "${e.toString()} ${const String.fromEnvironment('HOST', defaultValue: 'http://localhost:8080')}"; }
|
|
} else { err = "no url"; }
|
|
throw Exception(err);
|
|
}
|
|
|
|
Future<APIResponse<T>> sendFile(String url, File file, BuildContext context) async {
|
|
FormData formData = FormData.fromMap({
|
|
"file": await MultipartFile.fromFile(file.path, filename:file.path.split("/").last),
|
|
});
|
|
// ignore: use_build_context_synchronously
|
|
return _main(url, formData, "post", "send succeed", true, context, Options(contentType: 'multipart/form-data'));
|
|
}
|
|
|
|
Future getWithDownload(String url, String format, Map<String,dynamic> cache, String savePath, bool isWeb, BuildContext context) async {
|
|
String asLabel = "";
|
|
for (var key in cache.keys) {
|
|
if (!asLabel.contains(key)) { asLabel += "&${key}_aslabel=${cache[key]!}"; }
|
|
}
|
|
try { _mainDownload(url, "get", true, "&export=$format$asLabel", savePath, isWeb, context);
|
|
} catch (e) { /* */ }
|
|
}
|
|
|
|
Future<APIResponse<T>> getWithOffset(String url, bool force, BuildContext? context) async {
|
|
return _main(url, null, "get", "", force, context, null);
|
|
}
|
|
|
|
Future<APIResponse<T>> get(String url, bool force, BuildContext? context) async {
|
|
return _main(url, null, "get", "", force, context, null);
|
|
}
|
|
|
|
Future<APIResponse<T>> post(String url, Map<String, dynamic> values, BuildContext? context) async {
|
|
return _main(url, values, "post", "send succeed", true, context, null);
|
|
}
|
|
|
|
Future<APIResponse<T>> put(String url, Map<String, dynamic> values, BuildContext? context) async {
|
|
return _main(url, values, "put", "save succeed", true, context, null);
|
|
}
|
|
|
|
Future<APIResponse<T>> delete(String url, BuildContext? context) async {
|
|
return _main(url, null, "delete", "deletion succeed", true, context, null);
|
|
}
|
|
} |