feat: add upload logic.
This commit is contained in:
@@ -1,10 +1,10 @@
|
|||||||
import 'package:angel3_migration/angel3_migration.dart';
|
|
||||||
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
|
||||||
import 'package:dde_gesture_manager_api/src/config/plugins/orm.dart';
|
|
||||||
import 'package:dde_gesture_manager_api/models.dart';
|
|
||||||
import 'package:angel3_configuration/angel3_configuration.dart';
|
import 'package:angel3_configuration/angel3_configuration.dart';
|
||||||
|
import 'package:angel3_migration/angel3_migration.dart';
|
||||||
import 'package:angel3_migration_runner/angel3_migration_runner.dart';
|
import 'package:angel3_migration_runner/angel3_migration_runner.dart';
|
||||||
import 'package:angel3_migration_runner/postgres.dart';
|
import 'package:angel3_migration_runner/postgres.dart';
|
||||||
|
import 'package:angel3_orm_postgres/angel3_orm_postgres.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/models.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/src/config/plugins/orm.dart';
|
||||||
import 'package:file/local.dart';
|
import 'package:file/local.dart';
|
||||||
import 'package:logging/logging.dart';
|
import 'package:logging/logging.dart';
|
||||||
|
|
||||||
@@ -28,6 +28,7 @@ void main(List<String> args) async {
|
|||||||
var migrationRunner = PostgresMigrationRunner(connection, migrations: [
|
var migrationRunner = PostgresMigrationRunner(connection, migrations: [
|
||||||
UserMigration(),
|
UserMigration(),
|
||||||
UserSeed(),
|
UserSeed(),
|
||||||
|
SchemeMigration(),
|
||||||
]);
|
]);
|
||||||
await runMigrations(migrationRunner, args);
|
await runMigrations(migrationRunner, args);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ class Apis {
|
|||||||
|
|
||||||
static final system = SystemApis();
|
static final system = SystemApis();
|
||||||
static final auth = AuthApis();
|
static final auth = AuthApis();
|
||||||
|
static final scheme = SchemeApis();
|
||||||
}
|
}
|
||||||
|
|
||||||
class AuthApis {
|
class AuthApis {
|
||||||
@@ -15,6 +16,8 @@ class AuthApis {
|
|||||||
String get loginOrSignup => [path, 'login_or_signup'].joinPath();
|
String get loginOrSignup => [path, 'login_or_signup'].joinPath();
|
||||||
|
|
||||||
String confirmSignup({required StringParam accessKey}) => [path, 'confirm_sign_up', accessKey].joinPath();
|
String confirmSignup({required StringParam accessKey}) => [path, 'confirm_sign_up', accessKey].joinPath();
|
||||||
|
|
||||||
|
String get status => [path, 'status'].joinPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
class SystemApis {
|
class SystemApis {
|
||||||
@@ -23,6 +26,14 @@ class SystemApis {
|
|||||||
String get appVersion => [path, 'app-version'].joinPath();
|
String get appVersion => [path, 'app-version'].joinPath();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class SchemeApis {
|
||||||
|
static final String path = '/scheme';
|
||||||
|
|
||||||
|
String get upload => [path, 'upload'].joinPath();
|
||||||
|
|
||||||
|
String get userUploads => [path, 'user', 'uploads'].joinPath();
|
||||||
|
}
|
||||||
|
|
||||||
final _paramsMap = {
|
final _paramsMap = {
|
||||||
'IntParam': IntParam.nameOnRoute,
|
'IntParam': IntParam.nameOnRoute,
|
||||||
'DoubleParam': DoubleParam.nameOnRoute,
|
'DoubleParam': DoubleParam.nameOnRoute,
|
||||||
|
|||||||
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
export 'src/models/user.dart';
|
export 'src/models/user.dart';
|
||||||
export 'src/models/app_version.dart';
|
export 'src/models/app_version.dart';
|
||||||
export 'src/models/login_success.dart';
|
export 'src/models/login_success.dart';
|
||||||
|
export 'src/models/scheme.dart';
|
||||||
@@ -9,7 +9,7 @@ Future<void> configureServer(Angel app) async {
|
|||||||
allowCookie: false,
|
allowCookie: false,
|
||||||
deserializer: (p) async => (UserQuery()..where!.id.equals(int.parse(p)))
|
deserializer: (p) async => (UserQuery()..where!.id.equals(int.parse(p)))
|
||||||
.getOne(app.container!.make<orm.QueryExecutor>())
|
.getOne(app.container!.make<orm.QueryExecutor>())
|
||||||
.then((value) => value.value),
|
.then((value) => value.isNotEmpty ? value.value : User(email: '')),
|
||||||
serializer: (p) => p.id ?? '',
|
serializer: (p) => p.id ?? '',
|
||||||
);
|
);
|
||||||
await auth.configureServer(app);
|
await auth.configureServer(app);
|
||||||
|
|||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import 'package:angel3_orm/angel3_orm.dart';
|
||||||
|
import 'package:angel3_serialize/angel3_serialize.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/src/models/base_model.dart';
|
||||||
|
import 'package:angel3_migration/angel3_migration.dart';
|
||||||
|
import 'package:optional/optional.dart';
|
||||||
|
|
||||||
|
part 'scheme.g.dart';
|
||||||
|
|
||||||
|
@serializable
|
||||||
|
@orm
|
||||||
|
abstract class _Scheme extends BaseModel {
|
||||||
|
@Column(isNullable: false, indexType: IndexType.unique)
|
||||||
|
@SerializableField(isNullable: false)
|
||||||
|
String? get uuid;
|
||||||
|
|
||||||
|
@Column(isNullable: false)
|
||||||
|
@SerializableField(isNullable: false)
|
||||||
|
String? get name;
|
||||||
|
|
||||||
|
@Column(isNullable: false, indexType: IndexType.standardIndex)
|
||||||
|
@SerializableField(isNullable: true, exclude: true)
|
||||||
|
int? uid;
|
||||||
|
|
||||||
|
@Column(type: ColumnType.text)
|
||||||
|
String? description;
|
||||||
|
|
||||||
|
@Column(isNullable: false, indexType: IndexType.standardIndex)
|
||||||
|
@SerializableField(defaultValue: false, isNullable: false)
|
||||||
|
bool? get shared;
|
||||||
|
|
||||||
|
@Column(type: ColumnType.jsonb)
|
||||||
|
@SerializableField()
|
||||||
|
@DefaultsTo([])
|
||||||
|
List? get gestures;
|
||||||
|
}
|
||||||
@@ -20,5 +20,9 @@ abstract class _User extends BaseModel {
|
|||||||
@SerializableField(isNullable: true, exclude: true)
|
@SerializableField(isNullable: true, exclude: true)
|
||||||
String? get password;
|
String? get password;
|
||||||
|
|
||||||
|
@Column(isNullable: false)
|
||||||
|
@SerializableField(defaultValue: false)
|
||||||
|
bool? get blocked;
|
||||||
|
|
||||||
String secret(String salt) => base64.encode(Hmac(sha256, salt.codeUnits).convert((password ?? '').codeUnits).bytes);
|
String secret(String salt) => base64.encode(Hmac(sha256, salt.codeUnits).convert((password ?? '').codeUnits).bytes);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import 'package:angel3_auth/angel3_auth.dart';
|
|||||||
import 'package:angel3_framework/angel3_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:dde_gesture_manager_api/apis.dart';
|
import 'package:dde_gesture_manager_api/apis.dart';
|
||||||
import 'package:dde_gesture_manager_api/models.dart';
|
import 'package:dde_gesture_manager_api/models.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/src/routes/controllers/middlewares.dart';
|
||||||
import 'package:mailer/mailer.dart';
|
import 'package:mailer/mailer.dart';
|
||||||
import 'package:mailer/smtp_server.dart';
|
import 'package:mailer/smtp_server.dart';
|
||||||
import 'package:uuid/uuid.dart';
|
import 'package:uuid/uuid.dart';
|
||||||
@@ -48,6 +49,8 @@ Future configureServer(Angel app) async {
|
|||||||
return res.notFound();
|
return res.notFound();
|
||||||
} else if (user.value.password != userParams.password) {
|
} else if (user.value.password != userParams.password) {
|
||||||
return res.unauthorized();
|
return res.unauthorized();
|
||||||
|
} else if (user.value.blocked == true) {
|
||||||
|
return res.forbidden();
|
||||||
} else {
|
} else {
|
||||||
var angelAuth = req.container!.make<AngelAuth>();
|
var angelAuth = req.container!.make<AngelAuth>();
|
||||||
await angelAuth.loginById(user.value.id!, req, res);
|
await angelAuth.loginById(user.value.id!, req, res);
|
||||||
@@ -75,4 +78,14 @@ Future configureServer(Angel app) async {
|
|||||||
}
|
}
|
||||||
return res.render('sign_up_result.html', {'success': false});
|
return res.render('sign_up_result.html', {'success': false});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
Apis.auth.status,
|
||||||
|
chain(
|
||||||
|
[
|
||||||
|
jwtMiddleware(),
|
||||||
|
(req, res) => req.user.blocked == false ? res.noContent() : res.forbidden(),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,6 +2,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:angel3_framework/angel3_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
import 'package:angel3_orm/angel3_orm.dart' as orm;
|
import 'package:angel3_orm/angel3_orm.dart' as orm;
|
||||||
|
import 'package:dde_gesture_manager_api/models.dart';
|
||||||
import 'package:dde_gesture_manager_api/src/config/plugins/redis_cache.dart';
|
import 'package:dde_gesture_manager_api/src/config/plugins/redis_cache.dart';
|
||||||
import 'package:neat_cache/neat_cache.dart';
|
import 'package:neat_cache/neat_cache.dart';
|
||||||
|
|
||||||
@@ -20,6 +21,16 @@ extension ResponseNoContent on ResponseContext {
|
|||||||
statusCode = HttpStatus.unauthorized;
|
statusCode = HttpStatus.unauthorized;
|
||||||
return close();
|
return close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
forbidden() {
|
||||||
|
statusCode = HttpStatus.forbidden;
|
||||||
|
return close();
|
||||||
|
}
|
||||||
|
|
||||||
|
unProcessableEntity() {
|
||||||
|
statusCode = HttpStatus.unprocessableEntity;
|
||||||
|
return close();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
extension QueryWhereId on orm.Query {
|
extension QueryWhereId on orm.Query {
|
||||||
@@ -32,6 +43,10 @@ extension QueryExecutor on RequestContext {
|
|||||||
orm.QueryExecutor get queryExecutor => container!.make<orm.QueryExecutor>();
|
orm.QueryExecutor get queryExecutor => container!.make<orm.QueryExecutor>();
|
||||||
}
|
}
|
||||||
|
|
||||||
extension RedisExecutor on RequestContext {
|
extension RedisClient on RequestContext {
|
||||||
Cache get cache => container!.make<RedisCache>().cache;
|
Cache get cache => container!.make<RedisCache>().cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extension JWTUserInstance on RequestContext {
|
||||||
|
User get user => container!.make<User>();
|
||||||
|
}
|
||||||
|
|||||||
@@ -2,16 +2,15 @@ import 'package:angel3_auth/angel3_auth.dart';
|
|||||||
import 'package:angel3_framework/angel3_framework.dart';
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
|
||||||
import 'package:dde_gesture_manager_api/models.dart';
|
import 'package:dde_gesture_manager_api/models.dart';
|
||||||
|
import '../controllers/controller_extensions.dart';
|
||||||
|
|
||||||
RequestHandler jwtMiddleware() {
|
RequestHandler jwtMiddleware() {
|
||||||
return (RequestContext req, ResponseContext res, {bool throwError = true}) async {
|
return (RequestContext req, ResponseContext res, {bool throwError = true}) async {
|
||||||
bool _reject(ResponseContext res) {
|
bool _reject(ResponseContext res) {
|
||||||
if (throwError) {
|
if (throwError) {
|
||||||
res.statusCode = 403;
|
res.forbidden();
|
||||||
throw AngelHttpException.forbidden();
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (req.container != null) {
|
if (req.container != null) {
|
||||||
|
|||||||
@@ -0,0 +1,60 @@
|
|||||||
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:angel3_framework/angel3_framework.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/apis.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/src/models/scheme.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/src/routes/controllers/middlewares.dart';
|
||||||
|
import 'package:logging/logging.dart';
|
||||||
|
import 'controller_extensions.dart';
|
||||||
|
|
||||||
|
Future configureServer(Angel app) async {
|
||||||
|
final _log = Logger('scheme_controller');
|
||||||
|
|
||||||
|
app.post(
|
||||||
|
Apis.scheme.upload,
|
||||||
|
chain(
|
||||||
|
[
|
||||||
|
jwtMiddleware(),
|
||||||
|
(req, res) async {
|
||||||
|
try {
|
||||||
|
var scheme = SchemeSerializer.fromMap(req.bodyAsMap);
|
||||||
|
var schemeQuery = SchemeQuery();
|
||||||
|
schemeQuery.where!.uuid.equals(scheme.uuid!);
|
||||||
|
var one = await schemeQuery.getOne(req.queryExecutor);
|
||||||
|
schemeQuery = SchemeQuery();
|
||||||
|
schemeQuery.values.copyFrom(scheme);
|
||||||
|
schemeQuery.values.uid = int.parse(req.user.id!);
|
||||||
|
if (one.isEmpty) {
|
||||||
|
await schemeQuery.insert(req.queryExecutor);
|
||||||
|
} else {
|
||||||
|
schemeQuery.whereId = int.parse(one.value.id!);
|
||||||
|
await schemeQuery.updateOne(req.queryExecutor);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
_log.severe(e);
|
||||||
|
return res.unProcessableEntity();
|
||||||
|
}
|
||||||
|
return res.noContent();
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
app.get(
|
||||||
|
Apis.scheme.userUploads,
|
||||||
|
chain(
|
||||||
|
[
|
||||||
|
jwtMiddleware(),
|
||||||
|
(req, res) async {
|
||||||
|
var schemeQuery = SchemeQuery();
|
||||||
|
schemeQuery.where!.uid.equals(int.parse(req.user.id!));
|
||||||
|
schemeQuery.orderBy(SchemeFields.updatedAt, descending: true);
|
||||||
|
return schemeQuery.get(req.queryExecutor).then((value) => value.map((e) => {
|
||||||
|
'name': e.name,
|
||||||
|
'description': e.description,
|
||||||
|
}).toList());
|
||||||
|
},
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -2,6 +2,7 @@ import 'package:angel3_framework/angel3_framework.dart';
|
|||||||
import 'package:file/file.dart';
|
import 'package:file/file.dart';
|
||||||
import 'controllers/auth_controllers.dart' as auth_controllers;
|
import 'controllers/auth_controllers.dart' as auth_controllers;
|
||||||
import 'controllers/system_controllers.dart' as system_controllers;
|
import 'controllers/system_controllers.dart' as system_controllers;
|
||||||
|
import 'controllers/scheme_controllers.dart' as scheme_controllers;
|
||||||
|
|
||||||
/// Put your app routes here!
|
/// Put your app routes here!
|
||||||
///
|
///
|
||||||
@@ -22,6 +23,7 @@ AngelConfigurer configureServer(FileSystem fileSystem) {
|
|||||||
// Typically, you want to mount controllers first, after any global middleware.
|
// Typically, you want to mount controllers first, after any global middleware.
|
||||||
await app.configure(system_controllers.configureServerWithFileSystem(fileSystem));
|
await app.configure(system_controllers.configureServerWithFileSystem(fileSystem));
|
||||||
await app.configure(auth_controllers.configureServer);
|
await app.configure(auth_controllers.configureServer);
|
||||||
|
await app.configure(scheme_controllers.configureServer);
|
||||||
|
|
||||||
// Throw a 404 if no route matched the request.
|
// Throw a 404 if no route matched the request.
|
||||||
app.fallback((req, res) => throw AngelHttpException.notFound());
|
app.fallback((req, res) => throw AngelHttpException.notFound());
|
||||||
|
|||||||
+33
-5
@@ -3,6 +3,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:dde_gesture_manager/constants/sp_keys.dart';
|
import 'package:dde_gesture_manager/constants/sp_keys.dart';
|
||||||
import 'package:dde_gesture_manager/extensions.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/helper.dart';
|
||||||
import 'package:dde_gesture_manager/utils/notificator.dart';
|
import 'package:dde_gesture_manager/utils/notificator.dart';
|
||||||
import 'package:dde_gesture_manager_api/apis.dart';
|
import 'package:dde_gesture_manager_api/apis.dart';
|
||||||
@@ -13,7 +14,12 @@ typedef T BeanBuilder<T>(Map res);
|
|||||||
|
|
||||||
typedef T HandleRespBuild<T>(http.Response resp);
|
typedef T HandleRespBuild<T>(http.Response resp);
|
||||||
|
|
||||||
getStatusCodeFunc<int>(Map resp) => resp["statusCode"];
|
typedef int GetStatusCodeFunc(Map resp);
|
||||||
|
|
||||||
|
int getStatusCodeFunc(Map resp) => resp["statusCode"] as int;
|
||||||
|
|
||||||
|
BeanBuilder<List<T>> listRespBuilderWrap<T>(BeanBuilder<T> builder) =>
|
||||||
|
(Map resp) => (resp['list'] as List).map<T>((e) => builder(e)).toList();
|
||||||
|
|
||||||
class HttpErrorCode extends Error {
|
class HttpErrorCode extends Error {
|
||||||
int statusCode;
|
int statusCode;
|
||||||
@@ -40,11 +46,13 @@ class Api {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static HandleRespBuild<T> _handleRespBuild<T>(BeanBuilder<T> builder) => (http.Response resp) {
|
static HandleRespBuild<T> _handleRespBuild<T>(BeanBuilder<T> builder) => (http.Response resp) {
|
||||||
if (builder == getStatusCodeFunc) return builder({"statusCode": resp.statusCode});
|
if (builder is GetStatusCodeFunc) return builder({"statusCode": resp.statusCode});
|
||||||
T res;
|
T res;
|
||||||
try {
|
try {
|
||||||
res = builder(json.decode(resp.body));
|
var decodeBody = json.decode(utf8.decode(resp.bodyBytes));
|
||||||
|
res = decodeBody is Map ? builder(decodeBody) : builder({'list': decodeBody});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
e.sout();
|
||||||
throw HttpErrorCode(resp.statusCode, message: resp.body);
|
throw HttpErrorCode(resp.statusCode, message: resp.body);
|
||||||
}
|
}
|
||||||
return res;
|
return res;
|
||||||
@@ -67,7 +75,7 @@ class Api {
|
|||||||
path: path,
|
path: path,
|
||||||
),
|
),
|
||||||
headers: <String, String>{
|
headers: <String, String>{
|
||||||
HttpHeaders.contentTypeHeader: ContentType.json.value,
|
HttpHeaders.contentTypeHeader: ContentType.json.toString(),
|
||||||
}..addAll(
|
}..addAll(
|
||||||
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
|
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
|
||||||
)
|
)
|
||||||
@@ -98,7 +106,7 @@ class Api {
|
|||||||
),
|
),
|
||||||
body: jsonEncode(body),
|
body: jsonEncode(body),
|
||||||
headers: <String, String>{
|
headers: <String, String>{
|
||||||
HttpHeaders.contentTypeHeader: ContentType.json.value,
|
HttpHeaders.contentTypeHeader: ContentType.json.toString(),
|
||||||
}..addAll(
|
}..addAll(
|
||||||
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
|
ignoreToken ? {} : {HttpHeaders.authorizationHeader: 'Bearer ${H().sp.getString(SPKeys.accessToken)}'}),
|
||||||
)
|
)
|
||||||
@@ -132,4 +140,24 @@ class Api {
|
|||||||
ignoreToken: true,
|
ignoreToken: true,
|
||||||
ignoreErrorHandle: ignoreErrorHandle,
|
ignoreErrorHandle: ignoreErrorHandle,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
static Future<bool> checkAuthStatus() => _get<int>(Apis.auth.status, getStatusCodeFunc, ignoreErrorHandle: true)
|
||||||
|
.then((value) => value == HttpStatus.noContent);
|
||||||
|
|
||||||
|
static Future<bool> 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<List<Scheme>> userUploads() =>
|
||||||
|
_get(Apis.scheme.userUploads, listRespBuilderWrap(SchemeSerializer.fromMap));
|
||||||
}
|
}
|
||||||
|
|||||||
+13
-1
@@ -3,6 +3,7 @@ import 'package:dde_gesture_manager/constants/sp_keys.dart';
|
|||||||
import 'package:dde_gesture_manager/constants/supported_locales.dart';
|
import 'package:dde_gesture_manager/constants/supported_locales.dart';
|
||||||
import 'package:dde_gesture_manager/extensions.dart';
|
import 'package:dde_gesture_manager/extensions.dart';
|
||||||
import 'package:dde_gesture_manager/generated/codegen_loader.g.dart';
|
import 'package:dde_gesture_manager/generated/codegen_loader.g.dart';
|
||||||
|
import 'package:dde_gesture_manager/http/api.dart';
|
||||||
import 'package:dde_gesture_manager/models/configs.dart';
|
import 'package:dde_gesture_manager/models/configs.dart';
|
||||||
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
||||||
import 'package:dde_gesture_manager/models/settings.provider.dart';
|
import 'package:dde_gesture_manager/models/settings.provider.dart';
|
||||||
@@ -68,7 +69,18 @@ class MyApp extends StatelessWidget {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
firstChild: Builder(builder: (context) {
|
firstChild: Builder(builder: (context) {
|
||||||
Future.microtask(() => initEvents(context));
|
Future.microtask(() {
|
||||||
|
initEvents(context);
|
||||||
|
if (H().lastCheckAuthStatusTime != null &&
|
||||||
|
H().lastCheckAuthStatusTime!.difference(DateTime.now()) < Duration(minutes: 10)) return;
|
||||||
|
if (context.read<ConfigsProvider>().accessToken.notNull) {
|
||||||
|
Api.checkAuthStatus().then((value) {
|
||||||
|
if (!value) context.read<ConfigsProvider>().setProps(email: '', accessToken: '');
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
H().lastCheckAuthStatusTime = DateTime.now();
|
||||||
|
}
|
||||||
|
});
|
||||||
return Container();
|
return Container();
|
||||||
}),
|
}),
|
||||||
secondChild: HomePage(),
|
secondChild: HomePage(),
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ class Scheme {
|
|||||||
@ProviderModelProp()
|
@ProviderModelProp()
|
||||||
List<GestureProp>? gestures;
|
List<GestureProp>? gestures;
|
||||||
|
|
||||||
bool get readOnly => uploaded == true || fromMarket == true || id == Uuid.NAMESPACE_NIL;
|
bool get readOnly => fromMarket == true || id == Uuid.NAMESPACE_NIL;
|
||||||
|
|
||||||
Scheme.parse(scheme) {
|
Scheme.parse(scheme) {
|
||||||
if (scheme is String) scheme = json.decode(scheme);
|
if (scheme is String) scheme = json.decode(scheme);
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:adaptive_scrollbar/adaptive_scrollbar.dart';
|
import 'package:adaptive_scrollbar/adaptive_scrollbar.dart';
|
||||||
import 'package:dde_gesture_manager/constants/constants.dart';
|
import 'package:dde_gesture_manager/constants/constants.dart';
|
||||||
import 'package:dde_gesture_manager/extensions.dart';
|
import 'package:dde_gesture_manager/extensions.dart';
|
||||||
|
import 'package:dde_gesture_manager/http/api.dart';
|
||||||
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
||||||
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
|
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
|
||||||
import 'package:dde_gesture_manager/models/local_schemes_provider.dart';
|
import 'package:dde_gesture_manager/models/local_schemes_provider.dart';
|
||||||
@@ -297,14 +298,13 @@ class GestureEditor extends StatelessWidget {
|
|||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.only(left: 10),
|
padding: const EdgeInsets.only(left: 10),
|
||||||
child: DButton.upload(
|
child: DButton.upload(
|
||||||
enabled: schemeProvider.uploaded == false,
|
enabled: schemeProvider.readOnly == false,
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
if (context.read<ConfigsProvider>().accessToken.isNull) {
|
if (context.read<ConfigsProvider>().accessToken.isNull) {
|
||||||
return Notificator.showAlert(
|
return Notificator.showAlert(
|
||||||
title: LocaleKeys.info_login_for_upload_title.tr(),
|
title: LocaleKeys.info_login_for_upload_title.tr(),
|
||||||
description: LocaleKeys.info_login_for_upload_description.tr(),
|
description: LocaleKeys.info_login_for_upload_description.tr(),
|
||||||
).then((value) {
|
).then((value) {
|
||||||
value.sout();
|
|
||||||
if (value == CustomButton.positiveButton) {
|
if (value == CustomButton.positiveButton) {
|
||||||
context
|
context
|
||||||
.read<ContentLayoutProvider>()
|
.read<ContentLayoutProvider>()
|
||||||
@@ -317,7 +317,27 @@ class GestureEditor extends StatelessWidget {
|
|||||||
description: LocaleKeys.info_upload_and_share_description.tr(),
|
description: LocaleKeys.info_upload_and_share_description.tr(),
|
||||||
positiveButtonTitle: LocaleKeys.str_share.tr(),
|
positiveButtonTitle: LocaleKeys.str_share.tr(),
|
||||||
negativeButtonTitle: LocaleKeys.str_cancel.tr(),
|
negativeButtonTitle: LocaleKeys.str_cancel.tr(),
|
||||||
);
|
).then((value) {
|
||||||
|
bool? _share;
|
||||||
|
if (value == CustomButton.positiveButton)
|
||||||
|
_share = true;
|
||||||
|
else if (value == CustomButton.negativeButton) _share = false;
|
||||||
|
|
||||||
|
if (_share != null) {
|
||||||
|
Api.uploadScheme(scheme: schemeProvider, share: _share).then((value) {
|
||||||
|
if (value) {
|
||||||
|
Notificator.success(context, title: LocaleKeys.info_upload_success.tr());
|
||||||
|
var localSchemesProvider = context.read<LocalSchemesProvider>();
|
||||||
|
var localSchemeEntry = localSchemesProvider.schemes!
|
||||||
|
.firstWhere((ele) => ele.scheme.id == schemeProvider.id);
|
||||||
|
localSchemeEntry.scheme.uploaded = true;
|
||||||
|
localSchemeEntry.save(localSchemesProvider);
|
||||||
|
} else {
|
||||||
|
Notificator.error(context, title: LocaleKeys.info_upload_failed.tr());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
});
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|||||||
@@ -1,10 +1,10 @@
|
|||||||
import 'package:auto_size_text/auto_size_text.dart';
|
|
||||||
import 'package:dde_gesture_manager/constants/constants.dart';
|
import 'package:dde_gesture_manager/constants/constants.dart';
|
||||||
import 'package:dde_gesture_manager/extensions.dart';
|
import 'package:dde_gesture_manager/extensions.dart';
|
||||||
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
||||||
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
|
import 'package:dde_gesture_manager/models/content_layout.provider.dart';
|
||||||
import 'package:dde_gesture_manager/widgets/dde_button.dart';
|
import 'package:dde_gesture_manager/widgets/dde_button.dart';
|
||||||
import 'package:dde_gesture_manager/widgets/login.dart';
|
import 'package:dde_gesture_manager/widgets/login.dart';
|
||||||
|
import 'package:dde_gesture_manager/widgets/me.dart';
|
||||||
import 'package:flutter/cupertino.dart';
|
import 'package:flutter/cupertino.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
@@ -82,33 +82,7 @@ class MarketOrMe extends StatelessWidget {
|
|||||||
Widget buildMeContent(BuildContext context) {
|
Widget buildMeContent(BuildContext context) {
|
||||||
var accessToken = context.watch<ConfigsProvider>().accessToken;
|
var accessToken = context.watch<ConfigsProvider>().accessToken;
|
||||||
if (accessToken.isNull) return LoginWidget();
|
if (accessToken.isNull) return LoginWidget();
|
||||||
|
return MeWidget();
|
||||||
return Padding(
|
|
||||||
padding: EdgeInsets.symmetric(vertical: 10),
|
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
Row(
|
|
||||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
|
||||||
children: [
|
|
||||||
Icon(Icons.person, size: defaultButtonHeight),
|
|
||||||
Flexible(
|
|
||||||
child: AutoSizeText(
|
|
||||||
context.watch<ConfigsProvider>().email ?? '',
|
|
||||||
style: TextStyle(
|
|
||||||
fontSize: 18,
|
|
||||||
),
|
|
||||||
maxLines: 1,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
DButton.logout(
|
|
||||||
enabled: true,
|
|
||||||
onTap: () => context.read<ConfigsProvider>().setProps(accessToken: '', email: ''),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget buildMarketContent(BuildContext context) {
|
Widget buildMarketContent(BuildContext context) {
|
||||||
|
|||||||
@@ -34,6 +34,8 @@ class H {
|
|||||||
|
|
||||||
BuildContext get topContext => _topContext;
|
BuildContext get topContext => _topContext;
|
||||||
|
|
||||||
|
DateTime? lastCheckAuthStatusTime;
|
||||||
|
|
||||||
initTopContext(BuildContext context) {
|
initTopContext(BuildContext context) {
|
||||||
_topContext = context;
|
_topContext = context;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -54,6 +54,12 @@ class _LoginWidgetState extends State<LoginWidget> {
|
|||||||
title: LocaleKeys.info_sign_up_hint_title.tr(),
|
title: LocaleKeys.info_sign_up_hint_title.tr(),
|
||||||
description: LocaleKeys.info_sign_up_hint_description.tr(),
|
description: LocaleKeys.info_sign_up_hint_description.tr(),
|
||||||
);
|
);
|
||||||
|
else if (code == HttpStatus.forbidden)
|
||||||
|
Notificator.info(
|
||||||
|
context,
|
||||||
|
title: LocaleKeys.info_user_blocked_hint_title.tr(),
|
||||||
|
description: LocaleKeys.info_user_blocked_hint_description.tr(),
|
||||||
|
);
|
||||||
else
|
else
|
||||||
throw e;
|
throw e;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
import 'package:auto_size_text/auto_size_text.dart';
|
||||||
|
import 'package:dde_gesture_manager/constants/constants.dart';
|
||||||
|
import 'package:dde_gesture_manager/http/api.dart';
|
||||||
|
import 'package:dde_gesture_manager/models/configs.provider.dart';
|
||||||
|
import 'package:dde_gesture_manager_api/models.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:dde_gesture_manager/extensions.dart';
|
||||||
|
|
||||||
|
import 'dde_button.dart';
|
||||||
|
|
||||||
|
class MeWidget extends StatefulWidget {
|
||||||
|
const MeWidget({Key? key}) : super(key: key);
|
||||||
|
|
||||||
|
@override
|
||||||
|
_MeWidgetState createState() => _MeWidgetState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _MeWidgetState extends State<MeWidget> {
|
||||||
|
List<Scheme> uploads = [];
|
||||||
|
|
||||||
|
@override
|
||||||
|
void initState() {
|
||||||
|
super.initState();
|
||||||
|
Api.userUploads().then((value) {
|
||||||
|
if (mounted)
|
||||||
|
setState(() {
|
||||||
|
uploads = value;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
return Padding(
|
||||||
|
padding: EdgeInsets.symmetric(vertical: 10),
|
||||||
|
child: Column(
|
||||||
|
children: [
|
||||||
|
Row(
|
||||||
|
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||||
|
children: [
|
||||||
|
Icon(Icons.person, size: defaultButtonHeight),
|
||||||
|
Flexible(
|
||||||
|
child: AutoSizeText(
|
||||||
|
context.watch<ConfigsProvider>().email ?? '',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 18,
|
||||||
|
),
|
||||||
|
maxLines: 1,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
DButton.logout(
|
||||||
|
enabled: true,
|
||||||
|
onTap: () => context.read<ConfigsProvider>().setProps(accessToken: '', email: ''),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
Text('我的上传'),
|
||||||
|
Container(
|
||||||
|
height: 400,
|
||||||
|
child: ListView.builder(
|
||||||
|
itemBuilder: (context, index) => Text(uploads[index].name ?? ''),
|
||||||
|
itemCount: uploads.length,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -138,6 +138,14 @@
|
|||||||
"upload_and_share": {
|
"upload_and_share": {
|
||||||
"title": "Share the scheme at the same time?",
|
"title": "Share the scheme at the same time?",
|
||||||
"description": "If you select [Share], other users can see this scheme and download it;\nIf you select [Cancel], you can still find this scheme in the [My Upload] list and share."
|
"description": "If you select [Share], other users can see this scheme and download it;\nIf you select [Cancel], you can still find this scheme in the [My Upload] list and share."
|
||||||
|
},
|
||||||
|
"user_blocked_hint": {
|
||||||
|
"title": "The account has been blocked!",
|
||||||
|
"description": "If you have any questions, please contact me using email."
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"success": "Upload success ~",
|
||||||
|
"failed": "Upload failed.."
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"me": {
|
"me": {
|
||||||
|
|||||||
@@ -138,6 +138,14 @@
|
|||||||
"upload_and_share": {
|
"upload_and_share": {
|
||||||
"title": "是否同时分享到方案市场?",
|
"title": "是否同时分享到方案市场?",
|
||||||
"description": "如果选择[分享],其他用户可以看到本方案并下载使用;\n如果选择[放弃],您仍可以稍后在[我的上传]列表中找到本方案进行操作。"
|
"description": "如果选择[分享],其他用户可以看到本方案并下载使用;\n如果选择[放弃],您仍可以稍后在[我的上传]列表中找到本方案进行操作。"
|
||||||
|
},
|
||||||
|
"user_blocked_hint": {
|
||||||
|
"title": "该账号已被封禁!",
|
||||||
|
"description": "如有疑问请通过发送邮件联系"
|
||||||
|
},
|
||||||
|
"upload": {
|
||||||
|
"success": "上传成功~",
|
||||||
|
"failed": "上传失败。。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"me": {
|
"me": {
|
||||||
|
|||||||
Reference in New Issue
Block a user