diff --git a/lib/api/client.dart b/lib/api/client.dart index cf2556f..4b48db4 100644 --- a/lib/api/client.dart +++ b/lib/api/client.dart @@ -16,6 +16,7 @@ import 'tags.dart'; import 'task.dart'; import 'token.dart'; import 'user.dart'; +import '../globals.dart'; part 'client.g.dart'; @@ -245,6 +246,12 @@ abstract class _EHApi { @Query("tag") String? tag, @Query("category") String? category, @CancelRequest() CancelToken? cancel}); + @PUT('/shared_token') + @MultiPart() + Future> shareGallery(@Part(name: "gid") int gid, + {@Part(name: "expired") int? expired, + @Part(name: "type") String type = "gallery", + @CancelRequest() CancelToken? cancel}); @GET('/tag/{id}') // ignore: unused_element @@ -437,6 +444,7 @@ class EHApi extends __EHApi { "jpn_title": jpnTitle?.toString(), "max_length": maxLength?.toString(), "export_ad": exportAd?.toString(), + "share": shareToken, }; queries.removeWhere((key, value) => value == null); final newUri = uri diff --git a/lib/api/client.g.dart b/lib/api/client.g.dart index 65723b0..ff45268 100644 --- a/lib/api/client.g.dart +++ b/lib/api/client.g.dart @@ -1004,6 +1004,58 @@ class __EHApi implements _EHApi { return _value; } + @override + Future> shareGallery( + int gid, { + int? expired, + String type = "gallery", + CancelToken? cancel, + }) async { + final _extra = {}; + final queryParameters = {}; + queryParameters.removeWhere((k, v) => v == null); + final _headers = {}; + final _data = FormData(); + _data.fields.add(MapEntry( + 'gid', + gid.toString(), + )); + if (expired != null) { + _data.fields.add(MapEntry( + 'expired', + expired.toString(), + )); + } + _data.fields.add(MapEntry( + 'type', + type, + )); + final _result = await _dio.fetch>( + _setStreamType>(Options( + method: 'PUT', + headers: _headers, + extra: _extra, + contentType: 'multipart/form-data', + ) + .compose( + _dio.options, + '/shared_token', + queryParameters: queryParameters, + data: _data, + cancelToken: cancel, + ) + .copyWith( + baseUrl: _combineBaseUrls( + _dio.options.baseUrl, + baseUrl, + )))); + final _value = ApiResult.fromJson( + _result.data!, + (json) => SharedTokenWithUrl.fromJson(json as Map), + ); + return _value; + } + @override Future> _getTags( String id, { diff --git a/lib/api/token.dart b/lib/api/token.dart index caf9a9d..eb9806f 100644 --- a/lib/api/token.dart +++ b/lib/api/token.dart @@ -108,3 +108,15 @@ class SharedToken { } } } + +@JsonSerializable(createToJson: false) +class SharedTokenWithUrl { + const SharedTokenWithUrl({ + required this.token, + required this.url, + }); + final SharedToken token; + final String url; + factory SharedTokenWithUrl.fromJson(Map json) => + _$SharedTokenWithUrlFromJson(json); +} diff --git a/lib/api/token.g.dart b/lib/api/token.g.dart index fd3cf60..aaf97fe 100644 --- a/lib/api/token.g.dart +++ b/lib/api/token.g.dart @@ -62,3 +62,9 @@ Map _$GallerySharedTokenInfoToJson( { 'gid': instance.gid, }; + +SharedTokenWithUrl _$SharedTokenWithUrlFromJson(Map json) => + SharedTokenWithUrl( + token: SharedToken.fromJson(json['token'] as Map), + url: json['url'] as String, + ); diff --git a/lib/api/user.dart b/lib/api/user.dart index 777a441..9fc4431 100644 --- a/lib/api/user.dart +++ b/lib/api/user.dart @@ -9,7 +9,8 @@ enum UserPermission with EnumFlag { readGallery, editGallery, deleteGallery, - manageTasks; + manageTasks, + shareGallery; String localText(BuildContext context) { final i18n = AppLocalizations.of(context)!; @@ -22,11 +23,13 @@ enum UserPermission with EnumFlag { return i18n.deleteGallery; case UserPermission.manageTasks: return i18n.manageTasks; + case UserPermission.shareGallery: + return i18n.shareGallery; } } } -const userPermissionAll = 15; +const userPermissionAll = 31; class UserPermissions { UserPermissions(this.code); diff --git a/lib/components/gallery_info.dart b/lib/components/gallery_info.dart index 03471e4..f17c841 100644 --- a/lib/components/gallery_info.dart +++ b/lib/components/gallery_info.dart @@ -86,18 +86,21 @@ class _GalleryInfo extends State with ThemeModeWidget { controller: controller, slivers: [ SliverAppBar( - leading: IconButton( - icon: Icon(widget.isSelectMode ? Icons.close : Icons.arrow_back), - onPressed: () { - if (widget.isSelectMode) { - if (widget.onSelectChanged != null) { - widget.onSelectChanged!(false); - } - } else { - context.canPop() ? context.pop() : context.go("/"); - } - }, - ), + leading: shareToken != null && !widget.isSelectMode + ? Container() + : IconButton( + icon: Icon( + widget.isSelectMode ? Icons.close : Icons.arrow_back), + onPressed: () { + if (widget.isSelectMode) { + if (widget.onSelectChanged != null) { + widget.onSelectChanged!(false); + } + } else { + context.canPop() ? context.pop() : context.go("/"); + } + }, + ), title: SelectableText(widget.gData.meta.preferredTitle, maxLines: 1, minLines: 1), actions: [ diff --git a/lib/components/gallery_info_desktop.dart b/lib/components/gallery_info_desktop.dart index ba8aa11..f426b08 100644 --- a/lib/components/gallery_info_desktop.dart +++ b/lib/components/gallery_info_desktop.dart @@ -1,3 +1,4 @@ +import 'package:eh_downloader_flutter/globals.dart'; import 'package:flutter/gestures.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/app_localizations.dart'; @@ -94,28 +95,34 @@ class GalleryInfoDesktop extends StatelessWidget { SizedBox( width: 170, child: Column(children: [ - SelectableText.rich(TextSpan( - text: gData.meta.category, - style: TextStyle(color: cs.secondary), - mouseCursor: SystemMouseCursors.click, - recognizer: TapGestureRecognizer() - ..onTap = () { - context.pushNamed("/galleries", - queryParameters: { - "category": gData.meta.category - }); - })), - SelectableText.rich(TextSpan( - text: gData.meta.uploader, - style: TextStyle(color: cs.secondary), - mouseCursor: SystemMouseCursors.click, - recognizer: TapGestureRecognizer() - ..onTap = () { - context.pushNamed("/galleries", - queryParameters: { - "uploader": gData.meta.uploader - }); - })), + shareToken != null + ? SelectableText(gData.meta.category, + style: TextStyle(color: cs.secondary)) + : SelectableText.rich(TextSpan( + text: gData.meta.category, + style: TextStyle(color: cs.secondary), + mouseCursor: SystemMouseCursors.click, + recognizer: TapGestureRecognizer() + ..onTap = () { + context.pushNamed("/galleries", + queryParameters: { + "category": gData.meta.category + }); + })), + shareToken != null + ? SelectableText(gData.meta.uploader, + style: TextStyle(color: cs.secondary)) + : SelectableText.rich(TextSpan( + text: gData.meta.uploader, + style: TextStyle(color: cs.secondary), + mouseCursor: SystemMouseCursors.click, + recognizer: TapGestureRecognizer() + ..onTap = () { + context.pushNamed("/galleries", + queryParameters: { + "uploader": gData.meta.uploader + }); + })), _KeyValue( "${i18n.posted}${i18n.colon}", DateFormat.yMd(locale) diff --git a/lib/components/tag.dart b/lib/components/tag.dart index 31b6fba..af05bae 100644 --- a/lib/components/tag.dart +++ b/lib/components/tag.dart @@ -10,6 +10,9 @@ class TagWidget extends StatelessWidget { @override Widget build(BuildContext context) { + final t = + Text(name ?? (tag.tag.contains(':') ? tag.tag.split(':')[1] : tag.tag)); + if (shareToken != null) return t; return InkWell( onTap: () { context.pushNamed("/galleries", @@ -18,6 +21,6 @@ class TagWidget extends StatelessWidget { }, extra: GalleriesPageExtra(translatedTag: tag.translated)); }, - child: Text(name ?? (tag.tag.contains(':') ? tag.tag.split(':')[1] : tag.tag))); + child: t); } } diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 50256bb..892fdf3 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -314,5 +314,6 @@ } } }, - "enableServerTiming": "Enable server time tracking" + "enableServerTiming": "Enable server time tracking", + "shareGallery": "Share gallery" } diff --git a/lib/l10n/app_zh.arb b/lib/l10n/app_zh.arb index cf6f0c5..29560d8 100644 --- a/lib/l10n/app_zh.arb +++ b/lib/l10n/app_zh.arb @@ -314,5 +314,6 @@ } } }, - "enableServerTiming": "测量服务器所用时间" + "enableServerTiming": "测量服务器所用时间", + "shareGallery": "分享画廊" } diff --git a/lib/pages/gallery.dart b/lib/pages/gallery.dart index 0ad0039..1e2664d 100644 --- a/lib/pages/gallery.dart +++ b/lib/pages/gallery.dart @@ -151,12 +151,16 @@ class _GalleryPage extends State return Scaffold( appBar: _data == null ? AppBar( - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: () { - context.canPop() ? context.pop() : context.go("/gallery"); - }, - ), + leading: shareToken != null + ? Container() + : IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: () { + context.canPop() + ? context.pop() + : context.go("/gallery"); + }, + ), title: Text(title), actions: [ buildThemeModeIcon(context),