Browse Source

[flutter]: fix some ui bugs

appflowy 3 years ago
parent
commit
33b2eae174

+ 14 - 0
app_flowy/lib/workspace/application/trash/trash_bloc.dart

@@ -26,6 +26,16 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
       didReceiveTrash: (e) async* {
         yield state.copyWith(objects: e.trash);
       },
+      putback: (e) async* {
+        final result = await iTrash.putback(e.trashId);
+        result.fold((l) {}, (error) {});
+      },
+      delete: (e) async* {
+        final result = await iTrash.delete(e.trashId);
+        result.fold((l) {}, (error) {});
+      },
+      deleteAll: (e) async* {},
+      restoreAll: (e) async* {},
     );
   }
 
@@ -51,6 +61,10 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
 class TrashEvent with _$TrashEvent {
   const factory TrashEvent.initial() = Initial;
   const factory TrashEvent.didReceiveTrash(List<Trash> trash) = ReceiveTrash;
+  const factory TrashEvent.putback(String trashId) = Putback;
+  const factory TrashEvent.delete(String trashId) = Delete;
+  const factory TrashEvent.restoreAll() = RestoreAll;
+  const factory TrashEvent.deleteAll() = DeleteAll;
 }
 
 @freezed

+ 523 - 0
app_flowy/lib/workspace/application/trash/trash_bloc.freezed.dart

@@ -25,6 +25,26 @@ class _$TrashEventTearOff {
       trash,
     );
   }
+
+  Putback putback(String trashId) {
+    return Putback(
+      trashId,
+    );
+  }
+
+  Delete delete(String trashId) {
+    return Delete(
+      trashId,
+    );
+  }
+
+  RestoreAll restoreAll() {
+    return const RestoreAll();
+  }
+
+  DeleteAll deleteAll() {
+    return const DeleteAll();
+  }
 }
 
 /// @nodoc
@@ -36,12 +56,20 @@ mixin _$TrashEvent {
   TResult when<TResult extends Object?>({
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
   }) =>
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   TResult maybeWhen<TResult extends Object?>({
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
     required TResult orElse(),
   }) =>
       throw _privateConstructorUsedError;
@@ -49,12 +77,20 @@ mixin _$TrashEvent {
   TResult map<TResult extends Object?>({
     required TResult Function(Initial value) initial,
     required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
   }) =>
       throw _privateConstructorUsedError;
   @optionalTypeArgs
   TResult maybeMap<TResult extends Object?>({
     TResult Function(Initial value)? initial,
     TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
     required TResult orElse(),
   }) =>
       throw _privateConstructorUsedError;
@@ -115,6 +151,10 @@ class _$Initial implements Initial {
   TResult when<TResult extends Object?>({
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
   }) {
     return initial();
   }
@@ -124,6 +164,10 @@ class _$Initial implements Initial {
   TResult maybeWhen<TResult extends Object?>({
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
     required TResult orElse(),
   }) {
     if (initial != null) {
@@ -137,6 +181,10 @@ class _$Initial implements Initial {
   TResult map<TResult extends Object?>({
     required TResult Function(Initial value) initial,
     required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
   }) {
     return initial(this);
   }
@@ -146,6 +194,10 @@ class _$Initial implements Initial {
   TResult maybeMap<TResult extends Object?>({
     TResult Function(Initial value)? initial,
     TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
     required TResult orElse(),
   }) {
     if (initial != null) {
@@ -225,6 +277,10 @@ class _$ReceiveTrash implements ReceiveTrash {
   TResult when<TResult extends Object?>({
     required TResult Function() initial,
     required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
   }) {
     return didReceiveTrash(trash);
   }
@@ -234,6 +290,10 @@ class _$ReceiveTrash implements ReceiveTrash {
   TResult maybeWhen<TResult extends Object?>({
     TResult Function()? initial,
     TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
     required TResult orElse(),
   }) {
     if (didReceiveTrash != null) {
@@ -247,6 +307,10 @@ class _$ReceiveTrash implements ReceiveTrash {
   TResult map<TResult extends Object?>({
     required TResult Function(Initial value) initial,
     required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
   }) {
     return didReceiveTrash(this);
   }
@@ -256,6 +320,10 @@ class _$ReceiveTrash implements ReceiveTrash {
   TResult maybeMap<TResult extends Object?>({
     TResult Function(Initial value)? initial,
     TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
     required TResult orElse(),
   }) {
     if (didReceiveTrash != null) {
@@ -274,6 +342,461 @@ abstract class ReceiveTrash implements TrashEvent {
       throw _privateConstructorUsedError;
 }
 
+/// @nodoc
+abstract class $PutbackCopyWith<$Res> {
+  factory $PutbackCopyWith(Putback value, $Res Function(Putback) then) =
+      _$PutbackCopyWithImpl<$Res>;
+  $Res call({String trashId});
+}
+
+/// @nodoc
+class _$PutbackCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
+    implements $PutbackCopyWith<$Res> {
+  _$PutbackCopyWithImpl(Putback _value, $Res Function(Putback) _then)
+      : super(_value, (v) => _then(v as Putback));
+
+  @override
+  Putback get _value => super._value as Putback;
+
+  @override
+  $Res call({
+    Object? trashId = freezed,
+  }) {
+    return _then(Putback(
+      trashId == freezed
+          ? _value.trashId
+          : trashId // ignore: cast_nullable_to_non_nullable
+              as String,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$Putback implements Putback {
+  const _$Putback(this.trashId);
+
+  @override
+  final String trashId;
+
+  @override
+  String toString() {
+    return 'TrashEvent.putback(trashId: $trashId)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is Putback &&
+            (identical(other.trashId, trashId) ||
+                const DeepCollectionEquality().equals(other.trashId, trashId)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(trashId);
+
+  @JsonKey(ignore: true)
+  @override
+  $PutbackCopyWith<Putback> get copyWith =>
+      _$PutbackCopyWithImpl<Putback>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
+  }) {
+    return putback(trashId);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (putback != null) {
+      return putback(trashId);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
+  }) {
+    return putback(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (putback != null) {
+      return putback(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Putback implements TrashEvent {
+  const factory Putback(String trashId) = _$Putback;
+
+  String get trashId => throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  $PutbackCopyWith<Putback> get copyWith => throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $DeleteCopyWith<$Res> {
+  factory $DeleteCopyWith(Delete value, $Res Function(Delete) then) =
+      _$DeleteCopyWithImpl<$Res>;
+  $Res call({String trashId});
+}
+
+/// @nodoc
+class _$DeleteCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
+    implements $DeleteCopyWith<$Res> {
+  _$DeleteCopyWithImpl(Delete _value, $Res Function(Delete) _then)
+      : super(_value, (v) => _then(v as Delete));
+
+  @override
+  Delete get _value => super._value as Delete;
+
+  @override
+  $Res call({
+    Object? trashId = freezed,
+  }) {
+    return _then(Delete(
+      trashId == freezed
+          ? _value.trashId
+          : trashId // ignore: cast_nullable_to_non_nullable
+              as String,
+    ));
+  }
+}
+
+/// @nodoc
+
+class _$Delete implements Delete {
+  const _$Delete(this.trashId);
+
+  @override
+  final String trashId;
+
+  @override
+  String toString() {
+    return 'TrashEvent.delete(trashId: $trashId)';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) ||
+        (other is Delete &&
+            (identical(other.trashId, trashId) ||
+                const DeepCollectionEquality().equals(other.trashId, trashId)));
+  }
+
+  @override
+  int get hashCode =>
+      runtimeType.hashCode ^ const DeepCollectionEquality().hash(trashId);
+
+  @JsonKey(ignore: true)
+  @override
+  $DeleteCopyWith<Delete> get copyWith =>
+      _$DeleteCopyWithImpl<Delete>(this, _$identity);
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
+  }) {
+    return delete(trashId);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (delete != null) {
+      return delete(trashId);
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
+  }) {
+    return delete(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (delete != null) {
+      return delete(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class Delete implements TrashEvent {
+  const factory Delete(String trashId) = _$Delete;
+
+  String get trashId => throw _privateConstructorUsedError;
+  @JsonKey(ignore: true)
+  $DeleteCopyWith<Delete> get copyWith => throw _privateConstructorUsedError;
+}
+
+/// @nodoc
+abstract class $RestoreAllCopyWith<$Res> {
+  factory $RestoreAllCopyWith(
+          RestoreAll value, $Res Function(RestoreAll) then) =
+      _$RestoreAllCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class _$RestoreAllCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
+    implements $RestoreAllCopyWith<$Res> {
+  _$RestoreAllCopyWithImpl(RestoreAll _value, $Res Function(RestoreAll) _then)
+      : super(_value, (v) => _then(v as RestoreAll));
+
+  @override
+  RestoreAll get _value => super._value as RestoreAll;
+}
+
+/// @nodoc
+
+class _$RestoreAll implements RestoreAll {
+  const _$RestoreAll();
+
+  @override
+  String toString() {
+    return 'TrashEvent.restoreAll()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is RestoreAll);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
+  }) {
+    return restoreAll();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (restoreAll != null) {
+      return restoreAll();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
+  }) {
+    return restoreAll(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (restoreAll != null) {
+      return restoreAll(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class RestoreAll implements TrashEvent {
+  const factory RestoreAll() = _$RestoreAll;
+}
+
+/// @nodoc
+abstract class $DeleteAllCopyWith<$Res> {
+  factory $DeleteAllCopyWith(DeleteAll value, $Res Function(DeleteAll) then) =
+      _$DeleteAllCopyWithImpl<$Res>;
+}
+
+/// @nodoc
+class _$DeleteAllCopyWithImpl<$Res> extends _$TrashEventCopyWithImpl<$Res>
+    implements $DeleteAllCopyWith<$Res> {
+  _$DeleteAllCopyWithImpl(DeleteAll _value, $Res Function(DeleteAll) _then)
+      : super(_value, (v) => _then(v as DeleteAll));
+
+  @override
+  DeleteAll get _value => super._value as DeleteAll;
+}
+
+/// @nodoc
+
+class _$DeleteAll implements DeleteAll {
+  const _$DeleteAll();
+
+  @override
+  String toString() {
+    return 'TrashEvent.deleteAll()';
+  }
+
+  @override
+  bool operator ==(dynamic other) {
+    return identical(this, other) || (other is DeleteAll);
+  }
+
+  @override
+  int get hashCode => runtimeType.hashCode;
+
+  @override
+  @optionalTypeArgs
+  TResult when<TResult extends Object?>({
+    required TResult Function() initial,
+    required TResult Function(List<Trash> trash) didReceiveTrash,
+    required TResult Function(String trashId) putback,
+    required TResult Function(String trashId) delete,
+    required TResult Function() restoreAll,
+    required TResult Function() deleteAll,
+  }) {
+    return deleteAll();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeWhen<TResult extends Object?>({
+    TResult Function()? initial,
+    TResult Function(List<Trash> trash)? didReceiveTrash,
+    TResult Function(String trashId)? putback,
+    TResult Function(String trashId)? delete,
+    TResult Function()? restoreAll,
+    TResult Function()? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (deleteAll != null) {
+      return deleteAll();
+    }
+    return orElse();
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult map<TResult extends Object?>({
+    required TResult Function(Initial value) initial,
+    required TResult Function(ReceiveTrash value) didReceiveTrash,
+    required TResult Function(Putback value) putback,
+    required TResult Function(Delete value) delete,
+    required TResult Function(RestoreAll value) restoreAll,
+    required TResult Function(DeleteAll value) deleteAll,
+  }) {
+    return deleteAll(this);
+  }
+
+  @override
+  @optionalTypeArgs
+  TResult maybeMap<TResult extends Object?>({
+    TResult Function(Initial value)? initial,
+    TResult Function(ReceiveTrash value)? didReceiveTrash,
+    TResult Function(Putback value)? putback,
+    TResult Function(Delete value)? delete,
+    TResult Function(RestoreAll value)? restoreAll,
+    TResult Function(DeleteAll value)? deleteAll,
+    required TResult orElse(),
+  }) {
+    if (deleteAll != null) {
+      return deleteAll(this);
+    }
+    return orElse();
+  }
+}
+
+abstract class DeleteAll implements TrashEvent {
+  const factory DeleteAll() = _$DeleteAll;
+}
+
 /// @nodoc
 class _$TrashStateTearOff {
   const _$TrashStateTearOff();

+ 4 - 0
app_flowy/lib/workspace/domain/i_trash.dart

@@ -5,6 +5,10 @@ import 'package:flowy_sdk/protobuf/flowy-workspace/trash_create.pb.dart';
 
 abstract class ITrash {
   Future<Either<List<Trash>, WorkspaceError>> readTrash();
+
+  Future<Either<Unit, WorkspaceError>> putback(String trashId);
+
+  Future<Either<Unit, WorkspaceError>> delete(String trashId);
 }
 
 typedef TrashUpdatedCallback = void Function(Either<List<Trash>, WorkspaceError> trashOrFailed);

+ 10 - 0
app_flowy/lib/workspace/infrastructure/i_trash_impl.dart

@@ -18,6 +18,16 @@ class ITrashImpl implements ITrash {
       );
     });
   }
+
+  @override
+  Future<Either<Unit, WorkspaceError>> putback(String trashId) {
+    return repo.putback(trashId);
+  }
+
+  @override
+  Future<Either<Unit, WorkspaceError>> delete(String trashId) {
+    return repo.delete(trashId);
+  }
 }
 
 class ITrashListenerImpl extends ITrashListener {

+ 38 - 28
app_flowy/lib/workspace/presentation/stack_page/trash/trash_page.dart

@@ -52,37 +52,45 @@ class _TrashStackPageState extends State<TrashStackPage> {
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
+    const horizontalPadding = 80.0;
     return SizedBox.expand(
       child: Column(
         children: [
           _renderTopBar(theme),
           const VSpace(32),
-          Expanded(
-            child: ScrollbarListStack(
-              axis: Axis.vertical,
+          _renderTrashList(context),
+        ],
+        mainAxisAlignment: MainAxisAlignment.start,
+      ).padding(horizontal: horizontalPadding, vertical: 48),
+    );
+  }
+
+  Widget _renderTrashList(BuildContext context) {
+    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(),
+          axis: Axis.horizontal,
+          child: SizedBox(
+            width: TrashSizes.totalWidth,
+            child: CustomScrollView(
+              shrinkWrap: true,
+              physics: StyledScrollPhysics(),
               controller: _scrollController,
-              barSize: 10,
-              child: StyledSingleChildScrollView(
-                controller: ScrollController(),
-                axis: Axis.horizontal,
-                child: SizedBox(
-                  width: TrashSizes.totalWidth,
-                  child: CustomScrollView(
-                    shrinkWrap: true,
-                    physics: StyledScrollPhysics(),
-                    controller: _scrollController,
-                    slivers: [
-                      _renderListHeader(context),
-                      _renderListBody(context),
-                    ],
-                  ),
-                ),
-              ),
+              slivers: [
+                _renderListHeader(context),
+                _renderListBody(context),
+              ],
             ),
           ),
-        ],
-        mainAxisAlignment: MainAxisAlignment.start,
-      ).padding(horizontal: 80, vertical: 48),
+        ),
+      ),
     );
   }
 
@@ -99,7 +107,7 @@ class _TrashStackPageState extends State<TrashStackPage> {
               text: const FlowyText.medium('Restore all', fontSize: 12),
               icon: svg('editor/restore'),
               hoverColor: theme.hover,
-              onTap: () {},
+              onTap: () => context.read<TrashBloc>().add(const TrashEvent.restoreAll()),
             ),
           ),
           const HSpace(6),
@@ -109,7 +117,7 @@ class _TrashStackPageState extends State<TrashStackPage> {
               text: const FlowyText.medium('Delete all', fontSize: 12),
               icon: svg('editor/delete'),
               hoverColor: theme.hover,
-              onTap: () {},
+              onTap: () => context.read<TrashBloc>().add(const TrashEvent.deleteAll()),
             ),
           )
         ],
@@ -133,16 +141,18 @@ class _TrashStackPageState extends State<TrashStackPage> {
           return SliverList(
             delegate: SliverChildBuilderDelegate(
               (BuildContext context, int index) {
+                final object = state.objects[index];
                 return SizedBox(
                   height: 42,
                   child: TrashCell(
-                    object: state.objects[index],
-                    onRestore: () {},
-                    onDelete: () {},
+                    object: object,
+                    onRestore: () => context.read<TrashBloc>().add(TrashEvent.putback(object.id)),
+                    onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
                   ),
                 );
               },
               childCount: state.objects.length,
+              addAutomaticKeepAlives: false,
             ),
           );
         },

+ 2 - 1
app_flowy/lib/workspace/presentation/stack_page/trash/widget/sizes.dart

@@ -1,5 +1,6 @@
 class TrashSizes {
-  static double scale = 1;
+  static double scale = 0.8;
+  static double get headerHeight => 60 * scale;
   static double get fileNameWidth => 320 * scale;
   static double get lashModifyWidth => 230 * scale;
   static double get createTimeWidth => 230 * scale;

+ 1 - 0
app_flowy/lib/workspace/presentation/stack_page/trash/widget/trash_cell.dart

@@ -32,6 +32,7 @@ class TrashCell extends StatelessWidget {
           onPressed: onDelete,
           icon: svg("editor/delete"),
         ),
+        const HSpace(20),
       ],
     );
   }

+ 2 - 2
app_flowy/lib/workspace/presentation/stack_page/trash/widget/trash_header.dart

@@ -14,10 +14,10 @@ class TrashHeaderDelegate extends SliverPersistentHeaderDelegate {
   }
 
   @override
-  double get maxExtent => 60;
+  double get maxExtent => TrashSizes.headerHeight;
 
   @override
-  double get minExtent => 60;
+  double get minExtent => TrashSizes.headerHeight;
 
   @override
   bool shouldRebuild(covariant SliverPersistentHeaderDelegate oldDelegate) {

+ 19 - 13
app_flowy/lib/workspace/presentation/widgets/menu/menu.dart

@@ -1,6 +1,7 @@
 import 'package:app_flowy/workspace/presentation/widgets/menu/widget/top_bar.dart';
 import 'package:dartz/dartz.dart';
 import 'package:flowy_infra/size.dart';
+import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
 import 'package:flowy_infra_ui/widget/error_page.dart';
 import 'package:flowy_infra_ui/widget/spacing.dart';
 import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
@@ -175,21 +176,26 @@ class MenuList extends StatelessWidget {
     return ExpandableTheme(
       data: ExpandableThemeData(useInkWell: true, animationDuration: Durations.medium),
       child: Expanded(
-        child: ListView.separated(
-          itemCount: menuItems.length,
-          separatorBuilder: (context, index) {
-            if (index == 0) {
-              return const VSpace(29);
-            } else {
-              return const VSpace(24);
-            }
-          },
-          physics: const BouncingScrollPhysics(),
-          itemBuilder: (BuildContext context, int index) {
-            return menuItems[index];
-          },
+        child: ScrollConfiguration(
+          behavior: const ScrollBehavior(),
+          child: ListView.separated(
+            itemCount: menuItems.length,
+            separatorBuilder: (context, index) {
+              if (index == 0) {
+                return const VSpace(29);
+              } else {
+                return const VSpace(24);
+              }
+            },
+            physics: StyledScrollPhysics(),
+            itemBuilder: (BuildContext context, int index) {
+              return menuItems[index];
+            },
+          ),
         ),
       ),
     );
   }
 }
+
+class _NoGlowBehavior extends ScrollBehavior {}

+ 12 - 37
app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scroll_bar.dart

@@ -56,14 +56,6 @@ class ScrollbarState extends State<StyledScrollbar> {
     super.didUpdateWidget(oldWidget);
   }
 
-//  void calculateSize() {
-//    //[SB] Only hack I can find  to make the ScrollController update it's maxExtents.
-//    //Call this whenever the content changes, so the scrollbar can recalculate it's size
-//    widget.controller.jumpTo(widget.controller.position.pixels + 1);
-//    Future.microtask(() => widget.controller
-//        .animateTo(widget.controller.position.pixels - 1, duration: 100.milliseconds, curve: Curves.linear));
-//  }
-
   @override
   Widget build(BuildContext context) {
     final theme = context.watch<AppTheme>();
@@ -100,8 +92,7 @@ class ScrollbarState extends State<StyledScrollbar> {
         // Calculate the alignment for the handle, this is a value between 0 and 1,
         // it automatically takes the handle size into acct
         // ignore: omit_local_variable_types
-        double handleAlignment =
-            maxExtent == 0 ? 0 : widget.controller.offset / maxExtent;
+        double handleAlignment = maxExtent == 0 ? 0 : widget.controller.offset / maxExtent;
 
         // Convert handle alignment from [0, 1] to [-1, 1]
         handleAlignment *= 2.0;
@@ -116,13 +107,9 @@ class ScrollbarState extends State<StyledScrollbar> {
         // Hide the handle if content is < the viewExtent
         var showHandle = contentExtent > _viewExtent && contentExtent > 0;
         // Handle color
-        var handleColor = widget.handleColor ??
-            (theme.isDark ? theme.bg2.withOpacity(.2) : theme.bg2);
+        var handleColor = widget.handleColor ?? (theme.isDark ? theme.bg2.withOpacity(.2) : theme.bg2);
         // Track color
-        var trackColor = widget.trackColor ??
-            (theme.isDark
-                ? theme.bg2.withOpacity(.1)
-                : theme.bg2.withOpacity(.3));
+        var trackColor = widget.trackColor ?? (theme.isDark ? theme.bg2.withOpacity(.1) : theme.bg2.withOpacity(.3));
 
         //Layout the stack, it just contains a child, and
         return Stack(children: <Widget>[
@@ -132,12 +119,8 @@ class ScrollbarState extends State<StyledScrollbar> {
               alignment: const Alignment(1, 1),
               child: Container(
                 color: trackColor,
-                width: widget.axis == Axis.vertical
-                    ? widget.size
-                    : double.infinity,
-                height: widget.axis == Axis.horizontal
-                    ? widget.size
-                    : double.infinity,
+                width: widget.axis == Axis.vertical ? widget.size : double.infinity,
+                height: widget.axis == Axis.horizontal ? widget.size : double.infinity,
               ),
             ),
 
@@ -154,14 +137,10 @@ class ScrollbarState extends State<StyledScrollbar> {
               // HANDLE SHAPE
               child: MouseHoverBuilder(
                 builder: (_, isHovered) => Container(
-                  width:
-                      widget.axis == Axis.vertical ? widget.size : handleExtent,
-                  height: widget.axis == Axis.horizontal
-                      ? widget.size
-                      : handleExtent,
+                  width: widget.axis == Axis.vertical ? widget.size : handleExtent,
+                  height: widget.axis == Axis.horizontal ? widget.size : handleExtent,
                   decoration: BoxDecoration(
-                      color: handleColor.withOpacity(isHovered ? 1 : .85),
-                      borderRadius: Corners.s3Border),
+                      color: handleColor.withOpacity(isHovered ? 1 : .85), borderRadius: Corners.s3Border),
                 ),
               ),
             ),
@@ -173,19 +152,15 @@ class ScrollbarState extends State<StyledScrollbar> {
 
   void _handleHorizontalDrag(DragUpdateDetails details) {
     var pos = widget.controller.offset;
-    var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) /
-        _viewExtent;
-    widget.controller.jumpTo((pos + details.delta.dx * pxRatio)
-        .clamp(0.0, widget.controller.position.maxScrollExtent));
+    var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) / _viewExtent;
+    widget.controller.jumpTo((pos + details.delta.dx * pxRatio).clamp(0.0, widget.controller.position.maxScrollExtent));
     widget.onDrag?.call(details.delta.dx);
   }
 
   void _handleVerticalDrag(DragUpdateDetails details) {
     var pos = widget.controller.offset;
-    var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) /
-        _viewExtent;
-    widget.controller.jumpTo((pos + details.delta.dy * pxRatio)
-        .clamp(0.0, widget.controller.position.maxScrollExtent));
+    var pxRatio = (widget.controller.position.maxScrollExtent + _viewExtent) / _viewExtent;
+    widget.controller.jumpTo((pos + details.delta.dy * pxRatio).clamp(0.0, widget.controller.position.maxScrollExtent));
     widget.onDrag?.call(details.delta.dy);
   }
 }

+ 3 - 0
app_flowy/packages/flowy_infra_ui/lib/style_widget/scrolling/styled_scrollview.dart

@@ -9,6 +9,7 @@ class StyledSingleChildScrollView extends StatefulWidget {
   final Color? trackColor;
   final Color? handleColor;
   final ScrollController? controller;
+  final EdgeInsets? scrollbarPadding;
 
   final Widget? child;
 
@@ -20,6 +21,7 @@ class StyledSingleChildScrollView extends StatefulWidget {
     this.trackColor,
     this.handleColor,
     this.controller,
+    this.scrollbarPadding,
   }) : super(key: key);
 
   @override
@@ -55,6 +57,7 @@ class _StyledSingleChildScrollViewState extends State<StyledSingleChildScrollVie
       contentSize: widget.contentSize,
       axis: widget.axis,
       controller: scrollController,
+      scrollbarPadding: widget.scrollbarPadding,
       barSize: 12,
       trackColor: widget.trackColor,
       handleColor: widget.handleColor,