diff --git a/frontend/app_flowy/lib/plugins/trash/src/trash_cell.dart b/frontend/app_flowy/lib/plugins/trash/src/trash_cell.dart index 4d6604e4af..97f56ba89a 100644 --- a/frontend/app_flowy/lib/plugins/trash/src/trash_cell.dart +++ b/frontend/app_flowy/lib/plugins/trash/src/trash_cell.dart @@ -15,26 +15,41 @@ class TrashCell extends StatelessWidget { final VoidCallback onRestore; final VoidCallback onDelete; final TrashPB object; - const TrashCell({required this.object, required this.onRestore, required this.onDelete, Key? key}) : super(key: key); + const TrashCell( + {required this.object, + required this.onRestore, + required this.onDelete, + Key? key}) + : super(key: key); @override Widget build(BuildContext context) { final theme = context.watch(); return Row( children: [ - SizedBox(width: TrashSizes.fileNameWidth, child: FlowyText(object.name, fontSize: 12)), - SizedBox(width: TrashSizes.lashModifyWidth, child: FlowyText(dateFormatter(object.modifiedTime), fontSize: 12)), - SizedBox(width: TrashSizes.createTimeWidth, child: FlowyText(dateFormatter(object.createTime), fontSize: 12)), + SizedBox( + width: TrashSizes.fileNameWidth, + child: FlowyText(object.name, fontSize: 12)), + SizedBox( + width: TrashSizes.lashModifyWidth, + child: FlowyText(dateFormatter(object.modifiedTime), fontSize: 12)), + SizedBox( + width: TrashSizes.createTimeWidth, + child: FlowyText(dateFormatter(object.createTime), fontSize: 12)), const Spacer(), FlowyIconButton( - width: 16, + width: 26, onPressed: onRestore, + hoverColor: theme.hover, + iconPadding: const EdgeInsets.all(5), icon: svgWidget("editor/restore", color: theme.iconColor), ), const HSpace(20), FlowyIconButton( - width: 16, + width: 26, onPressed: onDelete, + hoverColor: theme.hover, + iconPadding: const EdgeInsets.all(5), icon: svgWidget("editor/delete", color: theme.iconColor), ), ], @@ -43,7 +58,8 @@ class TrashCell extends StatelessWidget { String dateFormatter($fixnum.Int64 inputTimestamps) { var outputFormat = DateFormat('MM/dd/yyyy hh:mm a'); - var date = DateTime.fromMillisecondsSinceEpoch(inputTimestamps.toInt() * 1000); + var date = + DateTime.fromMillisecondsSinceEpoch(inputTimestamps.toInt() * 1000); var outputDate = outputFormat.format(date); return outputDate; } diff --git a/frontend/app_flowy/lib/plugins/trash/trash_page.dart b/frontend/app_flowy/lib/plugins/trash/trash_page.dart new file mode 100644 index 0000000000..2c0ed36633 --- /dev/null +++ b/frontend/app_flowy/lib/plugins/trash/trash_page.dart @@ -0,0 +1,150 @@ +import 'package:app_flowy/generated/locale_keys.g.dart'; +import 'package:app_flowy/plugins/trash/src/sizes.dart'; +import 'package:app_flowy/plugins/trash/src/trash_header.dart'; +import 'package:app_flowy/startup/startup.dart'; +import 'package:easy_localization/easy_localization.dart'; +import 'package:flowy_infra/image.dart'; +import 'package:flowy_infra/theme.dart'; +import 'package:flowy_infra_ui/style_widget/button.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; +import 'package:flowy_infra_ui/style_widget/scrolling/styled_scrollview.dart'; +import 'package:flowy_infra_ui/style_widget/text.dart'; +import 'package:flowy_infra_ui/widget/spacing.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; +import 'package:styled_widget/styled_widget.dart'; + +import 'application/trash_bloc.dart'; +import 'src/trash_cell.dart'; + +class TrashPage extends StatefulWidget { + const TrashPage({Key? key}) : super(key: key); + + @override + State createState() => _TrashPageState(); +} + +class _TrashPageState extends State { + final ScrollController _scrollController = ScrollController(); + @override + Widget build(BuildContext context) { + final theme = context.watch(); + const horizontalPadding = 80.0; + return BlocProvider( + create: (context) => getIt()..add(const TrashEvent.initial()), + child: BlocBuilder( + builder: (context, state) { + return SizedBox.expand( + child: Column( + mainAxisAlignment: MainAxisAlignment.start, + children: [ + _renderTopBar(context, theme, state), + const VSpace(32), + _renderTrashList(context, state), + ], + ).padding(horizontal: horizontalPadding, vertical: 48), + ); + }, + ), + ); + } + + Widget _renderTrashList(BuildContext context, TrashState state) { + const barSize = 6.0; + return Expanded( + child: ScrollbarListStack( + axis: Axis.vertical, + controller: _scrollController, + scrollbarPadding: EdgeInsets.only(top: TrashSizes.headerHeight), + barSize: barSize, + child: StyledSingleChildScrollView( + controller: ScrollController(), + barSize: barSize, + axis: Axis.horizontal, + child: SizedBox( + width: TrashSizes.totalWidth, + child: ScrollConfiguration( + behavior: const ScrollBehavior().copyWith(scrollbars: false), + child: CustomScrollView( + shrinkWrap: true, + physics: StyledScrollPhysics(), + controller: _scrollController, + slivers: [ + _renderListHeader(context, state), + _renderListBody(context, state), + ], + ), + ), + ), + ), + ), + ); + } + + Widget _renderTopBar(BuildContext context, AppTheme theme, TrashState state) { + return SizedBox( + height: 36, + child: Row( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + FlowyText.semibold(LocaleKeys.trash_text.tr()), + const Spacer(), + IntrinsicWidth( + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.trash_restoreAll.tr(), + fontSize: 12), + leftIcon: svgWidget('editor/restore', color: theme.iconColor), + hoverColor: theme.hover, + onTap: () => context.read().add( + const TrashEvent.restoreAll(), + ), + ), + ), + const HSpace(6), + IntrinsicWidth( + child: FlowyButton( + text: FlowyText.medium(LocaleKeys.trash_deleteAll.tr(), + fontSize: 12), + leftIcon: svgWidget('editor/delete', color: theme.iconColor), + hoverColor: theme.hover, + onTap: () => + context.read().add(const TrashEvent.deleteAll()), + ), + ) + ], + ), + ); + } + + Widget _renderListHeader(BuildContext context, TrashState state) { + return SliverPersistentHeader( + delegate: TrashHeaderDelegate(), + floating: true, + pinned: true, + ); + } + + Widget _renderListBody(BuildContext context, TrashState state) { + return SliverList( + delegate: SliverChildBuilderDelegate( + (BuildContext context, int index) { + final object = state.objects[index]; + return SizedBox( + height: 42, + child: TrashCell( + object: object, + onRestore: () { + context.read().add(TrashEvent.putback(object.id)); + }, + onDelete: () => + context.read().add(TrashEvent.delete(object)), + ), + ); + }, + childCount: state.objects.length, + addAutomaticKeepAlives: false, + ), + ); + } +}