mirror of
https://github.com/lifegpc/eh_downloader_flutter.git
synced 2026-07-08 01:30:28 +08:00
Update create user dialog
This commit is contained in:
@@ -2,12 +2,12 @@ import 'dart:convert';
|
||||
|
||||
import 'package:cryptography/cryptography.dart';
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eh_downloader_flutter/api/file.dart';
|
||||
import 'package:retrofit/retrofit.dart';
|
||||
|
||||
import 'api_result.dart';
|
||||
import 'config.dart';
|
||||
import 'eh.dart';
|
||||
import 'file.dart';
|
||||
import 'gallery.dart';
|
||||
import 'status.dart';
|
||||
import 'tags.dart';
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
import 'package:enum_flag/enum_flag.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:json_annotation/json_annotation.dart';
|
||||
|
||||
part 'user.g.dart';
|
||||
@@ -7,16 +9,35 @@ enum UserPermission with EnumFlag {
|
||||
readGallery,
|
||||
editGallery,
|
||||
deleteGallery,
|
||||
manageTasks,
|
||||
manageTasks;
|
||||
|
||||
String localText(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context)!;
|
||||
switch (this) {
|
||||
case UserPermission.readGallery:
|
||||
return i18n.readGallery;
|
||||
case UserPermission.editGallery:
|
||||
return i18n.editGallery;
|
||||
case UserPermission.deleteGallery:
|
||||
return i18n.deleteGallery;
|
||||
case UserPermission.manageTasks:
|
||||
return i18n.manageTasks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const userPermissionAll = 15;
|
||||
|
||||
class UserPermissions {
|
||||
const UserPermissions(this.code);
|
||||
final int code;
|
||||
UserPermissions(this.code);
|
||||
int code;
|
||||
bool has(UserPermission permission) => code.hasFlag(permission);
|
||||
bool get isAll => code == userPermissionAll;
|
||||
int toJson() => code;
|
||||
void add(UserPermission flag) {
|
||||
code |= flag.value;
|
||||
}
|
||||
|
||||
static int toJson2(UserPermissions code) {
|
||||
return code.code;
|
||||
}
|
||||
@@ -25,6 +46,10 @@ class UserPermissions {
|
||||
return UserPermissions(code);
|
||||
}
|
||||
|
||||
void remove(UserPermission flag) {
|
||||
code &= ~flag.value;
|
||||
}
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
if (code & userPermissionAll == userPermissionAll) return "all";
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:eh_downloader_flutter/globals.dart';
|
||||
import '../globals.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import '../api/file.dart';
|
||||
|
||||
@@ -30,10 +30,12 @@ class UserCard extends StatelessWidget {
|
||||
style: TextStyle(color: cs.secondary))
|
||||
],
|
||||
)),
|
||||
IconButton(
|
||||
onPressed: () {},
|
||||
tooltip: i18n.edit,
|
||||
icon: const Icon(Icons.edit)),
|
||||
!user.isAdmin || (user.isAdmin && auth.isRoot == true)
|
||||
? IconButton(
|
||||
onPressed: () {},
|
||||
tooltip: i18n.edit,
|
||||
icon: const Icon(Icons.edit))
|
||||
: Container(),
|
||||
!user.isAdmin ||
|
||||
(user.isAdmin && auth.isRoot == true && user.id != 0)
|
||||
? IconButton(
|
||||
|
||||
78
lib/components/user_permissions_chips.dart
Normal file
78
lib/components/user_permissions_chips.dart
Normal file
@@ -0,0 +1,78 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import '../api/user.dart';
|
||||
|
||||
class UserPermissionsChips extends StatefulWidget {
|
||||
const UserPermissionsChips({super.key, this.permissions, this.onChanged});
|
||||
final UserPermissions? permissions;
|
||||
final ValueChanged<UserPermissions>? onChanged;
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _UserPermissionsChips();
|
||||
}
|
||||
|
||||
class _UserPermissionsChips extends State<UserPermissionsChips> {
|
||||
late UserPermissions _permissions;
|
||||
@override
|
||||
void initState() {
|
||||
_permissions = widget.permissions ?? UserPermissions(0);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _onChanged() {
|
||||
if (widget.onChanged != null) {
|
||||
widget.onChanged!(_permissions);
|
||||
}
|
||||
}
|
||||
|
||||
Widget _buildChips(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context)!;
|
||||
var list = <FilterChip>[
|
||||
FilterChip(
|
||||
label: Text(i18n.allPermissions),
|
||||
selected: _permissions.isAll,
|
||||
onSelected: (bool value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
_permissions.code = userPermissionAll;
|
||||
} else {
|
||||
_permissions.code = 0;
|
||||
}
|
||||
});
|
||||
_onChanged();
|
||||
},
|
||||
)
|
||||
];
|
||||
for (var flag in UserPermission.values) {
|
||||
list.add(FilterChip(
|
||||
label: Text(flag.localText(context)),
|
||||
selected: _permissions.has(flag),
|
||||
onSelected: (bool value) {
|
||||
setState(() {
|
||||
if (value) {
|
||||
_permissions.add(flag);
|
||||
} else {
|
||||
_permissions.remove(flag);
|
||||
}
|
||||
});
|
||||
_onChanged();
|
||||
},
|
||||
));
|
||||
}
|
||||
return Wrap(spacing: 5.0, children: list);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final i18n = AppLocalizations.of(context)!;
|
||||
return Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(bottom: 8),
|
||||
child: Row(mainAxisAlignment: MainAxisAlignment.start, children: [
|
||||
const Icon(Icons.person),
|
||||
Text(i18n.userPermissions, style: const TextStyle(fontSize: 20)),
|
||||
])),
|
||||
_buildChips(context),
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -58,7 +58,7 @@ class _GalleryDetailsPage extends State<GalleryDetailsPage> {
|
||||
try {
|
||||
_cancel = CancelToken();
|
||||
_isLoading = true;
|
||||
final data = (await api.getGallery(widget.gid)).unwrap();
|
||||
final data = (await api.getGallery(widget.gid, cancel: _cancel)).unwrap();
|
||||
if (!_cancel!.isCancelled) {
|
||||
setState(() {
|
||||
_meta = data.meta;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:eh_downloader_flutter/api/task.dart';
|
||||
import 'package:eh_downloader_flutter/components/labeled_checkbox.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import '../api/task.dart';
|
||||
import '../components/labeled_checkbox.dart';
|
||||
import '../components/number_field.dart';
|
||||
import '../globals.dart';
|
||||
import '../utils/parse_url.dart';
|
||||
|
||||
@@ -1,10 +1,16 @@
|
||||
import 'package:dio/dio.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:logging/logging.dart';
|
||||
import '../api/user.dart';
|
||||
import '../components/labeled_checkbox.dart';
|
||||
import '../components/user_permissions_chips.dart';
|
||||
import '../globals.dart';
|
||||
|
||||
final _log = Logger("NewUserPage");
|
||||
|
||||
class NewUserPage extends StatefulWidget {
|
||||
const NewUserPage({super.key});
|
||||
|
||||
@@ -19,7 +25,12 @@ class _NewUserPage extends State<NewUserPage> {
|
||||
String _username = "";
|
||||
String _password = "";
|
||||
bool _isAdmin = false;
|
||||
UserPermissions _permissions =
|
||||
UserPermissions(UserPermission.readGallery.value);
|
||||
bool _passwordVisible = false;
|
||||
CancelToken? _cancel;
|
||||
bool _isRequesting = false;
|
||||
int? _newUserId;
|
||||
|
||||
Widget _buildWithVecticalPadding(Widget child) {
|
||||
return Container(
|
||||
@@ -28,6 +39,34 @@ class _NewUserPage extends State<NewUserPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _request() async {
|
||||
setState(() {
|
||||
_isRequesting = true;
|
||||
});
|
||||
try {
|
||||
_cancel = CancelToken();
|
||||
// 关闭对话框不中断连接
|
||||
_newUserId = (await api.createUser(_username, _password,
|
||||
isAdmin: _isAdmin,
|
||||
permissions: _isAdmin ? null : _permissions.code))
|
||||
.unwrap();
|
||||
if (!_cancel!.isCancelled) {
|
||||
setState(() {
|
||||
_isRequesting = false;
|
||||
});
|
||||
}
|
||||
listener.tryEmit("new_user", _newUserId);
|
||||
} catch (e) {
|
||||
_log.severe("Failed to create new user: $e");
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cancel?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
if (!tryInitApi(context)) {
|
||||
@@ -39,6 +78,12 @@ class _NewUserPage extends State<NewUserPage> {
|
||||
});
|
||||
return Container();
|
||||
}
|
||||
if (_newUserId != null) {
|
||||
SchedulerBinding.instance.addPostFrameCallback((_) {
|
||||
context.canPop() ? context.pop() : context.go("/users");
|
||||
});
|
||||
return Container();
|
||||
}
|
||||
final i18n = AppLocalizations.of(context)!;
|
||||
final maxWidth = MediaQuery.of(context).size.width;
|
||||
return Container(
|
||||
@@ -51,6 +96,7 @@ class _NewUserPage extends State<NewUserPage> {
|
||||
child: Form(
|
||||
key: _formKey,
|
||||
child: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
@@ -117,6 +163,26 @@ class _NewUserPage extends State<NewUserPage> {
|
||||
}
|
||||
},
|
||||
label: Text(i18n.admin))),
|
||||
!_isAdmin
|
||||
? _buildWithVecticalPadding(UserPermissionsChips(
|
||||
permissions: _permissions,
|
||||
onChanged: (v) {
|
||||
setState(() {
|
||||
_permissions = v;
|
||||
});
|
||||
}))
|
||||
: Container(),
|
||||
Row(mainAxisAlignment: MainAxisAlignment.center, children: [
|
||||
ElevatedButton(
|
||||
onPressed: !_isRequesting &&
|
||||
_username.isNotEmpty &&
|
||||
_password.isNotEmpty
|
||||
? () {
|
||||
_request();
|
||||
}
|
||||
: null,
|
||||
child: Text(i18n.create))
|
||||
]),
|
||||
],
|
||||
))),
|
||||
);
|
||||
|
||||
@@ -206,5 +206,11 @@
|
||||
"user": "User",
|
||||
"edit": "Edit",
|
||||
"delete": "Delete",
|
||||
"createNewUser": "Create new user"
|
||||
"createNewUser": "Create new user",
|
||||
"readGallery": "Read gallery",
|
||||
"editGallery": "Edit gallery",
|
||||
"deleteGallery": "Delete gallery",
|
||||
"manageTasks": "Manage tasks",
|
||||
"allPermissions": "All permissions",
|
||||
"userPermissions": "User permissions"
|
||||
}
|
||||
|
||||
@@ -206,5 +206,11 @@
|
||||
"user": "用户",
|
||||
"edit": "编辑",
|
||||
"delete": "删除",
|
||||
"createNewUser": "新建用户"
|
||||
"createNewUser": "新建用户",
|
||||
"readGallery": "查看画廊",
|
||||
"editGallery": "编辑画廊",
|
||||
"deleteGallery": "删除画廊",
|
||||
"manageTasks": "管理任务",
|
||||
"allPermissions": "所有权限",
|
||||
"userPermissions": "用户权限"
|
||||
}
|
||||
|
||||
@@ -64,7 +64,7 @@ class _GalleryPage extends State<GalleryPage>
|
||||
try {
|
||||
_cancel = CancelToken();
|
||||
_isLoading = true;
|
||||
final data = (await api.getGallery(_gid)).unwrap();
|
||||
final data = (await api.getGallery(_gid, cancel: _cancel)).unwrap();
|
||||
_data = data;
|
||||
final fileData = (await api.getFiles(
|
||||
data.pages.map((e) => e.token).toList(),
|
||||
|
||||
@@ -23,12 +23,14 @@ class _UsersPage extends State<UsersPage> with ThemeModeWidget, IsTopWidget2 {
|
||||
List<BUser>? _users;
|
||||
bool _isLoading = false;
|
||||
CancelToken? _cancel;
|
||||
CancelToken? _cancel2;
|
||||
Object? _error;
|
||||
Future<void> _fetchData() async {
|
||||
_cancel2?.cancel();
|
||||
try {
|
||||
_cancel = CancelToken();
|
||||
_isLoading = true;
|
||||
final users = (await api.getUsers(all: true)).unwrap();
|
||||
final users = (await api.getUsers(all: true, cancel: _cancel)).unwrap();
|
||||
if (!_cancel!.isCancelled) {
|
||||
setState(() {
|
||||
_users = users;
|
||||
@@ -153,4 +155,38 @@ class _UsersPage extends State<UsersPage> with ThemeModeWidget, IsTopWidget2 {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_cancel?.cancel();
|
||||
_cancel2?.cancel();
|
||||
listener.removeEventListener("new_user", _onNewUser);
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
listener.on("new_user", _onNewUser);
|
||||
super.initState();
|
||||
}
|
||||
|
||||
void _onNewUser(dynamic arg) async {
|
||||
int uid = arg as int;
|
||||
try {
|
||||
_cancel2 = CancelToken();
|
||||
final u = (await api.getUser(id: uid, cancel: _cancel2)).unwrap();
|
||||
if (!_cancel2!.isCancelled) {
|
||||
setState(() {
|
||||
_users?.add(u);
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
if (!_cancel2!.isCancelled) {
|
||||
_log.severe("Failed to load user $uid:", e);
|
||||
setState(() {
|
||||
_error = e;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -27,7 +27,11 @@ class SinglePageViewerExtra {
|
||||
|
||||
class SinglePageViewer extends StatefulWidget {
|
||||
const SinglePageViewer(
|
||||
{super.key, required this.gid, required this.index, this.data, this.files});
|
||||
{super.key,
|
||||
required this.gid,
|
||||
required this.index,
|
||||
this.data,
|
||||
this.files});
|
||||
final GalleryData? data;
|
||||
final EhFiles? files;
|
||||
final int gid;
|
||||
@@ -89,7 +93,8 @@ class _SinglePageViewer extends State<SinglePageViewer>
|
||||
_cancel = CancelToken();
|
||||
_isLoading = true;
|
||||
if (_data == null) {
|
||||
final data = (await api.getGallery(widget.gid)).unwrap();
|
||||
final data =
|
||||
(await api.getGallery(widget.gid, cancel: _cancel)).unwrap();
|
||||
_data = data;
|
||||
}
|
||||
final fileData = (await api.getFiles(
|
||||
|
||||
Reference in New Issue
Block a user