mirror of
https://github.com/immich-app/immich.git
synced 2025-07-09 03:04:16 -04:00
feat: action buttons place holder (#19561)
* feat: action buttons place holder * lint * Update base_action_button.widget.dart Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com> --------- Co-authored-by: shenlong <139912620+shenlong-tanwen@users.noreply.github.com>
This commit is contained in:
parent
72a53f43c8
commit
97aabe466e
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class ArchiveActionButton extends ConsumerWidget {
|
||||||
|
const ArchiveActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.archive_outlined,
|
||||||
|
label: "archive".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -8,39 +8,46 @@ class BaseActionButton extends StatelessWidget {
|
|||||||
required this.iconData,
|
required this.iconData,
|
||||||
this.onPressed,
|
this.onPressed,
|
||||||
this.onLongPressed,
|
this.onLongPressed,
|
||||||
|
this.maxWidth = 90.0,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String label;
|
final String label;
|
||||||
final IconData iconData;
|
final IconData iconData;
|
||||||
|
final double maxWidth;
|
||||||
final void Function()? onPressed;
|
final void Function()? onPressed;
|
||||||
final void Function()? onLongPressed;
|
final void Function()? onLongPressed;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final minWidth =
|
final minWidth = context.isMobile ? context.width / 4.5 : 75.0;
|
||||||
context.isMobile ? MediaQuery.sizeOf(context).width / 4.5 : 75.0;
|
|
||||||
|
|
||||||
return MaterialButton(
|
return ConstrainedBox(
|
||||||
padding: const EdgeInsets.all(10),
|
constraints: BoxConstraints(
|
||||||
shape: const RoundedRectangleBorder(
|
maxWidth: maxWidth,
|
||||||
borderRadius: BorderRadius.all(Radius.circular(20)),
|
|
||||||
),
|
),
|
||||||
onPressed: onPressed,
|
child: MaterialButton(
|
||||||
onLongPress: onLongPressed,
|
padding: const EdgeInsets.all(10),
|
||||||
minWidth: minWidth,
|
shape: const RoundedRectangleBorder(
|
||||||
child: Column(
|
borderRadius: BorderRadius.all(Radius.circular(20)),
|
||||||
mainAxisAlignment: MainAxisAlignment.start,
|
),
|
||||||
crossAxisAlignment: CrossAxisAlignment.center,
|
onPressed: onPressed,
|
||||||
children: [
|
onLongPress: onLongPressed,
|
||||||
Icon(iconData, size: 24),
|
minWidth: minWidth,
|
||||||
const SizedBox(height: 8),
|
child: Column(
|
||||||
Text(
|
mainAxisAlignment: MainAxisAlignment.start,
|
||||||
label,
|
crossAxisAlignment: CrossAxisAlignment.center,
|
||||||
style: const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400),
|
children: [
|
||||||
maxLines: 3,
|
Icon(iconData, size: 24),
|
||||||
textAlign: TextAlign.center,
|
const SizedBox(height: 8),
|
||||||
),
|
Text(
|
||||||
],
|
label,
|
||||||
|
style:
|
||||||
|
const TextStyle(fontSize: 14.0, fontWeight: FontWeight.w400),
|
||||||
|
maxLines: 3,
|
||||||
|
textAlign: TextAlign.center,
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class DeletePermanentActionButton extends ConsumerWidget {
|
||||||
|
const DeletePermanentActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 110.0,
|
||||||
|
iconData: Icons.delete_forever,
|
||||||
|
label: "delete_dialog_title".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class DeleteLocalActionButton extends ConsumerWidget {
|
||||||
|
const DeleteLocalActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 95.0,
|
||||||
|
iconData: Icons.no_cell_outlined,
|
||||||
|
label: "control_bottom_app_bar_delete_from_local".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class DownloadActionButton extends ConsumerWidget {
|
||||||
|
const DownloadActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.download,
|
||||||
|
label: "download".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class EditDateTimeActionButton extends ConsumerWidget {
|
||||||
|
const EditDateTimeActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 95.0,
|
||||||
|
iconData: Icons.edit_calendar_outlined,
|
||||||
|
label: "control_bottom_app_bar_edit_time".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class EditLocationActionButton extends ConsumerWidget {
|
||||||
|
const EditLocationActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.edit_location_alt_outlined,
|
||||||
|
label: "control_bottom_app_bar_edit_location".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class FavoriteActionButton extends ConsumerWidget {
|
||||||
|
const FavoriteActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.favorite_border_rounded,
|
||||||
|
label: "favorite".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class MoveToLockFolderActionButton extends ConsumerWidget {
|
||||||
|
const MoveToLockFolderActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 100.0,
|
||||||
|
iconData: Icons.lock_outline_rounded,
|
||||||
|
label: "move_to_locked_folder".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class RemoveFromAlbumActionButton extends ConsumerWidget {
|
||||||
|
const RemoveFromAlbumActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.remove_circle_outline,
|
||||||
|
label: "remove_from_album".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class RemoveFromLockFolderActionButton extends ConsumerWidget {
|
||||||
|
const RemoveFromLockFolderActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 100.0,
|
||||||
|
iconData: Icons.lock_open_rounded,
|
||||||
|
label: "remove_from_locked_folder".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,8 +1,8 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
class ShareActionButton extends ConsumerWidget {
|
class ShareActionButton extends ConsumerWidget {
|
||||||
@ -13,7 +13,7 @@ class ShareActionButton extends ConsumerWidget {
|
|||||||
return BaseActionButton(
|
return BaseActionButton(
|
||||||
iconData:
|
iconData:
|
||||||
Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded,
|
Platform.isAndroid ? Icons.share_rounded : Icons.ios_share_rounded,
|
||||||
label: context.tr('share'),
|
label: 'share'.t(context: context),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class ShareLinkActionButton extends ConsumerWidget {
|
||||||
|
const ShareLinkActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.link_rounded,
|
||||||
|
label: "share_link".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class StackActionButton extends ConsumerWidget {
|
||||||
|
const StackActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.filter_none_rounded,
|
||||||
|
label: "stack".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,17 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class TrashActionButton extends ConsumerWidget {
|
||||||
|
const TrashActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
maxWidth: 85.0,
|
||||||
|
iconData: Icons.delete_outline_rounded,
|
||||||
|
label: "control_bottom_app_bar_trash_from_immich".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class UnarchiveActionButton extends ConsumerWidget {
|
||||||
|
const UnarchiveActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.unarchive_outlined,
|
||||||
|
label: "unarchive".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class UnFavoriteActionButton extends ConsumerWidget {
|
||||||
|
const UnFavoriteActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.favorite_rounded,
|
||||||
|
label: "unfavorite".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,16 @@
|
|||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/extensions/translate_extensions.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/base_action_button.widget.dart';
|
||||||
|
|
||||||
|
class UploadActionButton extends ConsumerWidget {
|
||||||
|
const UploadActionButton({super.key});
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
|
return BaseActionButton(
|
||||||
|
iconData: Icons.backup_outlined,
|
||||||
|
label: "upload".t(context: context),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
@ -1,16 +1,54 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
import 'package:hooks_riverpod/hooks_riverpod.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/archive_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/delete_local_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/download_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_date_time_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/edit_location_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/favorite_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/move_to_lock_folder_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/action_buttons/share_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/share_link_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/stack_action_button.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/trash_action_buton.widget.dart';
|
||||||
|
import 'package:immich_mobile/presentation/widgets/action_buttons/upload_action_button.widget.dart';
|
||||||
import 'package:immich_mobile/presentation/widgets/bottom_app_bar/base_bottom_sheet.widget.dart';
|
import 'package:immich_mobile/presentation/widgets/bottom_app_bar/base_bottom_sheet.widget.dart';
|
||||||
|
import 'package:immich_mobile/providers/server_info.provider.dart';
|
||||||
|
import 'package:immich_mobile/providers/timeline/multiselect.provider.dart';
|
||||||
|
|
||||||
class HomeBottomAppBar extends ConsumerWidget {
|
class HomeBottomAppBar extends ConsumerWidget {
|
||||||
const HomeBottomAppBar({super.key});
|
const HomeBottomAppBar({super.key});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context, WidgetRef ref) {
|
Widget build(BuildContext context, WidgetRef ref) {
|
||||||
return const BaseBottomSheet(
|
final multiselect = ref.watch(multiSelectProvider);
|
||||||
|
final isTrashEnable = ref.watch(
|
||||||
|
serverInfoProvider.select((state) => state.serverFeatures.trash),
|
||||||
|
);
|
||||||
|
|
||||||
|
return BaseBottomSheet(
|
||||||
|
initialChildSize: 0.25,
|
||||||
|
minChildSize: 0.22,
|
||||||
actions: [
|
actions: [
|
||||||
ShareActionButton(),
|
const ShareActionButton(),
|
||||||
|
if (multiselect.hasRemote) ...[
|
||||||
|
const ShareLinkActionButton(),
|
||||||
|
const ArchiveActionButton(),
|
||||||
|
const FavoriteActionButton(),
|
||||||
|
const DownloadActionButton(),
|
||||||
|
isTrashEnable
|
||||||
|
? const TrashActionButton()
|
||||||
|
: const DeletePermanentActionButton(),
|
||||||
|
const EditDateTimeActionButton(),
|
||||||
|
const EditLocationActionButton(),
|
||||||
|
const MoveToLockFolderActionButton(),
|
||||||
|
const StackActionButton(),
|
||||||
|
],
|
||||||
|
if (multiselect.hasLocal) ...[
|
||||||
|
const DeleteLocalActionButton(),
|
||||||
|
const UploadActionButton(),
|
||||||
|
],
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,14 @@ class MultiSelectState {
|
|||||||
});
|
});
|
||||||
|
|
||||||
bool get isEnabled => selectedAssets.isNotEmpty;
|
bool get isEnabled => selectedAssets.isNotEmpty;
|
||||||
|
bool get hasRemote => selectedAssets.any(
|
||||||
|
(asset) =>
|
||||||
|
asset.storage == AssetState.remote ||
|
||||||
|
asset.storage == AssetState.merged,
|
||||||
|
);
|
||||||
|
bool get hasLocal => selectedAssets.any(
|
||||||
|
(asset) => asset.storage == AssetState.local,
|
||||||
|
);
|
||||||
|
|
||||||
MultiSelectState copyWith({
|
MultiSelectState copyWith({
|
||||||
Set<BaseAsset>? selectedAssets,
|
Set<BaseAsset>? selectedAssets,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user