This commit is contained in:
2023-08-28 15:37:23 +08:00
parent ba77b72d46
commit 2cffe62963
13 changed files with 886 additions and 8 deletions

22
lib/api/api_result.dart Normal file
View File

@@ -0,0 +1,22 @@
import 'package:json_annotation/json_annotation.dart';
part 'api_result.g.dart';
@JsonSerializable(genericArgumentFactories: true)
class ApiResult<T> {
const ApiResult({
required this.ok,
required this.status,
this.data,
this.error,
});
factory ApiResult.fromJson(
Map<String, dynamic> json, T Function(Object?) fromJsonT) =>
_$ApiResultFromJson(json, fromJsonT);
final bool ok;
final int status;
final T? data;
final String? error;
Map<String, dynamic> toJson(Object? Function(T) toJsonT) =>
_$ApiResultToJson(this, toJsonT);
}

41
lib/api/api_result.g.dart Normal file
View File

@@ -0,0 +1,41 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'api_result.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
ApiResult<T> _$ApiResultFromJson<T>(
Map<String, dynamic> json,
T Function(Object? json) fromJsonT,
) =>
ApiResult<T>(
ok: json['ok'] as bool,
status: json['status'] as int,
data: _$nullableGenericFromJson(json['data'], fromJsonT),
error: json['error'] as String?,
);
Map<String, dynamic> _$ApiResultToJson<T>(
ApiResult<T> instance,
Object? Function(T value) toJsonT,
) =>
<String, dynamic>{
'ok': instance.ok,
'status': instance.status,
'data': _$nullableGenericToJson(instance.data, toJsonT),
'error': instance.error,
};
T? _$nullableGenericFromJson<T>(
Object? input,
T Function(Object? json) fromJson,
) =>
input == null ? null : fromJson(input);
Object? _$nullableGenericToJson<T>(
T? input,
Object? Function(T value) toJson,
) =>
input == null ? null : toJson(input);

19
lib/api/client.dart Normal file
View File

@@ -0,0 +1,19 @@
import 'package:dio/dio.dart';
import 'package:retrofit/retrofit.dart';
import 'api_result.dart';
import 'user.dart';
part 'client.g.dart';
@RestApi(parser: Parser.FlutterCompute)
abstract class EHApi {
factory EHApi(Dio dio, {String baseUrl}) = _EHApi;
@GET('/user')
Future<ApiResult<BUser>> getUser();
@GET('/user')
Future<ApiResult<BUser>> getUserById(@Query("id") int id);
@GET('/user')
Future<ApiResult<BUser>> getUserByUsername(
@Query("username") String username);
}

131
lib/api/client.g.dart Normal file
View File

@@ -0,0 +1,131 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'client.dart';
// **************************************************************************
// RetrofitGenerator
// **************************************************************************
// ignore_for_file: unnecessary_brace_in_string_interps,no_leading_underscores_for_local_identifiers
class _EHApi implements EHApi {
_EHApi(
this._dio, {
this.baseUrl,
});
final Dio _dio;
String? baseUrl;
@override
Future<ApiResult<BUser>> getUser() async {
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{};
final _headers = <String, dynamic>{};
final Map<String, dynamic>? _data = null;
final _result = await _dio
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
method: 'GET',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/user',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
))));
final value = await compute(deserializeApiResult<BUser>, _result.data!);
return value;
}
@override
Future<ApiResult<BUser>> getUserById(int id) async {
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'id': id};
final _headers = <String, dynamic>{};
final Map<String, dynamic>? _data = null;
final _result = await _dio
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
method: 'GET',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/user',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
))));
final value = await compute(deserializeApiResult<BUser>, _result.data!);
return value;
}
@override
Future<ApiResult<BUser>> getUserByUsername(String username) async {
const _extra = <String, dynamic>{};
final queryParameters = <String, dynamic>{r'username': username};
final _headers = <String, dynamic>{};
final Map<String, dynamic>? _data = null;
final _result = await _dio
.fetch<Map<String, dynamic>>(_setStreamType<ApiResult<BUser>>(Options(
method: 'GET',
headers: _headers,
extra: _extra,
)
.compose(
_dio.options,
'/user',
queryParameters: queryParameters,
data: _data,
)
.copyWith(
baseUrl: _combineBaseUrls(
_dio.options.baseUrl,
baseUrl,
))));
final value = await compute(deserializeApiResult<BUser>, _result.data!);
return value;
}
RequestOptions _setStreamType<T>(RequestOptions requestOptions) {
if (T != dynamic &&
!(requestOptions.responseType == ResponseType.bytes ||
requestOptions.responseType == ResponseType.stream)) {
if (T == String) {
requestOptions.responseType = ResponseType.plain;
} else {
requestOptions.responseType = ResponseType.json;
}
}
return requestOptions;
}
String _combineBaseUrls(
String dioBaseUrl,
String? baseUrl,
) {
if (baseUrl == null || baseUrl.trim().isEmpty) {
return dioBaseUrl;
}
final url = Uri.parse(baseUrl);
if (url.isAbsolute) {
return url.toString();
}
return Uri.parse(dioBaseUrl).resolveUri(url).toString();
}
}

30
lib/api/user.dart Normal file
View File

@@ -0,0 +1,30 @@
import 'package:json_annotation/json_annotation.dart';
part 'user.g.dart';
@JsonEnum(valueField: 'code')
enum UserPermission {
none(0),
readGallery(1),
editGallery(2),
all(3);
const UserPermission(this.code);
final int code;
}
@JsonSerializable()
class BUser {
const BUser({
required this.id,
required this.username,
required this.is_admin,
required this.permissions,
});
final int id;
final String username;
final bool is_admin;
final UserPermission permissions;
factory BUser.fromJson(Map<String, dynamic> json) => _$BUserFromJson(json);
Map<String, dynamic> toJson() => _$BUserToJson(this);
}

28
lib/api/user.g.dart Normal file
View File

@@ -0,0 +1,28 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
part of 'user.dart';
// **************************************************************************
// JsonSerializableGenerator
// **************************************************************************
BUser _$BUserFromJson(Map<String, dynamic> json) => BUser(
id: json['id'] as int,
username: json['username'] as String,
is_admin: json['is_admin'] as bool,
permissions: $enumDecode(_$UserPermissionEnumMap, json['permissions']),
);
Map<String, dynamic> _$BUserToJson(BUser instance) => <String, dynamic>{
'id': instance.id,
'username': instance.username,
'is_admin': instance.is_admin,
'permissions': _$UserPermissionEnumMap[instance.permissions]!,
};
const _$UserPermissionEnumMap = {
UserPermission.none: 0,
UserPermission.readGallery: 1,
UserPermission.editGallery: 2,
UserPermission.all: 3,
};

16
lib/globals.dart Normal file
View File

@@ -0,0 +1,16 @@
import 'dart:io';
import 'package:cookie_jar/cookie_jar.dart';
import 'package:dio/dio.dart';
import 'package:dio_cookie_manager/dio_cookie_manager.dart';
import 'package:path_provider/path_provider.dart';
final dio = Dio();
Future<void> prepareJar() async {
final Directory appDocDir = await getApplicationDocumentsDirectory();
final String appDocPath = appDocDir.path;
final jar = PersistCookieJar(
storage: FileStorage('$appDocPath/.eh-cookies/'),
);
dio.interceptors.add(CookieManager(jar));
}

16
lib/home.dart Normal file
View File

@@ -0,0 +1,16 @@
import 'package:flutter/material.dart';
class HomePage extends StatelessWidget {
const HomePage({Key? key}) : super(key: key);
static const String routeName = '/';
@override
Widget build(BuildContext context) {
return const Scaffold(
body: Center(
child: Text('Hello World!'),
),
);
}
}

View File

@@ -1,6 +1,20 @@
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
import 'globals.dart';
import 'home.dart';
void main() {
final _router = GoRouter(
routes: [
GoRoute(
path: HomePage.routeName,
builder: (context, state) => const HomePage(),
),
],
);
void main() async {
await prepareJar();
runApp(const MainApp());
}
@@ -9,12 +23,6 @@ class MainApp extends StatelessWidget {
@override
Widget build(BuildContext context) {
return const MaterialApp(
home: Scaffold(
body: Center(
child: Text('Hello World!'),
),
),
);
return MaterialApp.router(routerConfig: _router);
}
}