mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[flutter]: add scrollbar to trash list
This commit is contained in:
parent
931c638b93
commit
6e8ae0eca9
@ -10,7 +10,8 @@ part 'app_bloc.freezed.dart';
|
||||
|
||||
class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
final IApp iAppImpl;
|
||||
AppBloc(this.iAppImpl) : super(AppState.initial());
|
||||
final IAppListenr listener;
|
||||
AppBloc({required this.iAppImpl, required this.listener}) : super(AppState.initial());
|
||||
|
||||
@override
|
||||
Stream<AppState> mapEventToState(
|
||||
@ -18,6 +19,8 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
) async* {
|
||||
yield* event.map(
|
||||
initial: (e) async* {
|
||||
listener.start(viewsChangeCallback: _handleViewsOrFail);
|
||||
|
||||
yield* _fetchViews();
|
||||
},
|
||||
createView: (CreateView value) async* {
|
||||
@ -27,6 +30,24 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
return state.copyWith(successOrFailure: right(error));
|
||||
});
|
||||
},
|
||||
didReceiveViews: (e) async* {
|
||||
yield state.copyWith(views: e.views);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> close() async {
|
||||
await listener.stop();
|
||||
return super.close();
|
||||
}
|
||||
|
||||
void _handleViewsOrFail(Either<List<View>, WorkspaceError> viewsOrFail) {
|
||||
viewsOrFail.fold(
|
||||
(views) => add(AppEvent.didReceiveViews(views)),
|
||||
(error) {
|
||||
Log.error(error);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
@ -46,6 +67,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
|
||||
class AppEvent with _$AppEvent {
|
||||
const factory AppEvent.initial() = Initial;
|
||||
const factory AppEvent.createView(String name, String desc, ViewType viewType) = CreateView;
|
||||
const factory AppEvent.didReceiveViews(List<View> views) = ReceiveViews;
|
||||
}
|
||||
|
||||
@freezed
|
||||
|
@ -27,6 +27,12 @@ class _$AppEventTearOff {
|
||||
viewType,
|
||||
);
|
||||
}
|
||||
|
||||
ReceiveViews didReceiveViews(List<View> views) {
|
||||
return ReceiveViews(
|
||||
views,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
@ -39,12 +45,14 @@ mixin _$AppEvent {
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String name, String desc, ViewType viewType)
|
||||
createView,
|
||||
required TResult Function(List<View> views) didReceiveViews,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String name, String desc, ViewType viewType)? createView,
|
||||
TResult Function(List<View> views)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@ -52,12 +60,14 @@ mixin _$AppEvent {
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(CreateView value) createView,
|
||||
required TResult Function(ReceiveViews value) didReceiveViews,
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(CreateView value)? createView,
|
||||
TResult Function(ReceiveViews value)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) =>
|
||||
throw _privateConstructorUsedError;
|
||||
@ -118,6 +128,7 @@ class _$Initial implements Initial {
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String name, String desc, ViewType viewType)
|
||||
createView,
|
||||
required TResult Function(List<View> views) didReceiveViews,
|
||||
}) {
|
||||
return initial();
|
||||
}
|
||||
@ -127,6 +138,7 @@ class _$Initial implements Initial {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String name, String desc, ViewType viewType)? createView,
|
||||
TResult Function(List<View> views)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
@ -140,6 +152,7 @@ class _$Initial implements Initial {
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(CreateView value) createView,
|
||||
required TResult Function(ReceiveViews value) didReceiveViews,
|
||||
}) {
|
||||
return initial(this);
|
||||
}
|
||||
@ -149,6 +162,7 @@ class _$Initial implements Initial {
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(CreateView value)? createView,
|
||||
TResult Function(ReceiveViews value)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (initial != null) {
|
||||
@ -250,6 +264,7 @@ class _$CreateView implements CreateView {
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String name, String desc, ViewType viewType)
|
||||
createView,
|
||||
required TResult Function(List<View> views) didReceiveViews,
|
||||
}) {
|
||||
return createView(name, desc, viewType);
|
||||
}
|
||||
@ -259,6 +274,7 @@ class _$CreateView implements CreateView {
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String name, String desc, ViewType viewType)? createView,
|
||||
TResult Function(List<View> views)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (createView != null) {
|
||||
@ -272,6 +288,7 @@ class _$CreateView implements CreateView {
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(CreateView value) createView,
|
||||
required TResult Function(ReceiveViews value) didReceiveViews,
|
||||
}) {
|
||||
return createView(this);
|
||||
}
|
||||
@ -281,6 +298,7 @@ class _$CreateView implements CreateView {
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(CreateView value)? createView,
|
||||
TResult Function(ReceiveViews value)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (createView != null) {
|
||||
@ -302,6 +320,126 @@ abstract class CreateView implements AppEvent {
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
abstract class $ReceiveViewsCopyWith<$Res> {
|
||||
factory $ReceiveViewsCopyWith(
|
||||
ReceiveViews value, $Res Function(ReceiveViews) then) =
|
||||
_$ReceiveViewsCopyWithImpl<$Res>;
|
||||
$Res call({List<View> views});
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$ReceiveViewsCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
|
||||
implements $ReceiveViewsCopyWith<$Res> {
|
||||
_$ReceiveViewsCopyWithImpl(
|
||||
ReceiveViews _value, $Res Function(ReceiveViews) _then)
|
||||
: super(_value, (v) => _then(v as ReceiveViews));
|
||||
|
||||
@override
|
||||
ReceiveViews get _value => super._value as ReceiveViews;
|
||||
|
||||
@override
|
||||
$Res call({
|
||||
Object? views = freezed,
|
||||
}) {
|
||||
return _then(ReceiveViews(
|
||||
views == freezed
|
||||
? _value.views
|
||||
: views // ignore: cast_nullable_to_non_nullable
|
||||
as List<View>,
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
|
||||
class _$ReceiveViews implements ReceiveViews {
|
||||
const _$ReceiveViews(this.views);
|
||||
|
||||
@override
|
||||
final List<View> views;
|
||||
|
||||
@override
|
||||
String toString() {
|
||||
return 'AppEvent.didReceiveViews(views: $views)';
|
||||
}
|
||||
|
||||
@override
|
||||
bool operator ==(dynamic other) {
|
||||
return identical(this, other) ||
|
||||
(other is ReceiveViews &&
|
||||
(identical(other.views, views) ||
|
||||
const DeepCollectionEquality().equals(other.views, views)));
|
||||
}
|
||||
|
||||
@override
|
||||
int get hashCode =>
|
||||
runtimeType.hashCode ^ const DeepCollectionEquality().hash(views);
|
||||
|
||||
@JsonKey(ignore: true)
|
||||
@override
|
||||
$ReceiveViewsCopyWith<ReceiveViews> get copyWith =>
|
||||
_$ReceiveViewsCopyWithImpl<ReceiveViews>(this, _$identity);
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult when<TResult extends Object?>({
|
||||
required TResult Function() initial,
|
||||
required TResult Function(String name, String desc, ViewType viewType)
|
||||
createView,
|
||||
required TResult Function(List<View> views) didReceiveViews,
|
||||
}) {
|
||||
return didReceiveViews(views);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeWhen<TResult extends Object?>({
|
||||
TResult Function()? initial,
|
||||
TResult Function(String name, String desc, ViewType viewType)? createView,
|
||||
TResult Function(List<View> views)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (didReceiveViews != null) {
|
||||
return didReceiveViews(views);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult map<TResult extends Object?>({
|
||||
required TResult Function(Initial value) initial,
|
||||
required TResult Function(CreateView value) createView,
|
||||
required TResult Function(ReceiveViews value) didReceiveViews,
|
||||
}) {
|
||||
return didReceiveViews(this);
|
||||
}
|
||||
|
||||
@override
|
||||
@optionalTypeArgs
|
||||
TResult maybeMap<TResult extends Object?>({
|
||||
TResult Function(Initial value)? initial,
|
||||
TResult Function(CreateView value)? createView,
|
||||
TResult Function(ReceiveViews value)? didReceiveViews,
|
||||
required TResult orElse(),
|
||||
}) {
|
||||
if (didReceiveViews != null) {
|
||||
return didReceiveViews(this);
|
||||
}
|
||||
return orElse();
|
||||
}
|
||||
}
|
||||
|
||||
abstract class ReceiveViews implements AppEvent {
|
||||
const factory ReceiveViews(List<View> views) = _$ReceiveViews;
|
||||
|
||||
List<View> get views => throw _privateConstructorUsedError;
|
||||
@JsonKey(ignore: true)
|
||||
$ReceiveViewsCopyWith<ReceiveViews> get copyWith =>
|
||||
throw _privateConstructorUsedError;
|
||||
}
|
||||
|
||||
/// @nodoc
|
||||
class _$AppStateTearOff {
|
||||
const _$AppStateTearOff();
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:app_flowy/workspace/domain/i_app.dart';
|
||||
import 'package:flowy_log/flowy_log.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
||||
|
@ -78,7 +78,12 @@ class HomeDepsResolver {
|
||||
(user, _) => MenuUserBloc(getIt<IUser>(param1: user), getIt<IUserListener>(param1: user)));
|
||||
|
||||
// App
|
||||
getIt.registerFactoryParam<AppBloc, String, void>((appId, _) => AppBloc(getIt<IApp>(param1: appId)));
|
||||
getIt.registerFactoryParam<AppBloc, String, void>(
|
||||
(appId, _) => AppBloc(
|
||||
iAppImpl: getIt<IApp>(param1: appId),
|
||||
listener: getIt<IAppListenr>(param1: appId),
|
||||
),
|
||||
);
|
||||
getIt.registerFactoryParam<AppListenBloc, String, void>(
|
||||
(appId, _) => AppListenBloc(getIt<IAppListenr>(param1: appId)));
|
||||
|
||||
|
@ -1,9 +1,13 @@
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/trash/trash_bloc.dart';
|
||||
import 'package:app_flowy/workspace/domain/page_stack/page_stack.dart';
|
||||
import 'package:app_flowy/workspace/presentation/stack_page/trash/widget/sizes.dart';
|
||||
import 'package:app_flowy/workspace/presentation/stack_page/trash/widget/trash_cell.dart';
|
||||
import 'package:flowy_infra/image.dart';
|
||||
import 'package:flowy_infra/theme.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/style_widget/button.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
@ -29,7 +33,7 @@ class TrashStackContext extends HomeStackContext {
|
||||
|
||||
@override
|
||||
Widget render() {
|
||||
return const TrashStackPage(key: ObjectKey('TrashStackPage'));
|
||||
return const TrashStackPage(key: ValueKey('TrashStackPage'));
|
||||
}
|
||||
|
||||
@override
|
||||
@ -44,6 +48,7 @@ class TrashStackPage extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _TrashStackPageState extends State<TrashStackPage> {
|
||||
final ScrollController _scrollController = ScrollController();
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = context.watch<AppTheme>();
|
||||
@ -53,12 +58,26 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
||||
_renderTopBar(theme),
|
||||
const VSpace(32),
|
||||
Expanded(
|
||||
child: CustomScrollView(
|
||||
controller: ScrollController(),
|
||||
slivers: [
|
||||
_renderListHeader(context),
|
||||
_renderListBody(context),
|
||||
],
|
||||
child: ScrollbarListStack(
|
||||
axis: Axis.vertical,
|
||||
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),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -3,4 +3,7 @@ class TrashSizes {
|
||||
static double get fileNameWidth => 320 * scale;
|
||||
static double get lashModifyWidth => 230 * scale;
|
||||
static double get createTimeWidth => 230 * scale;
|
||||
static double get padding => 100 * scale;
|
||||
static double get totalWidth =>
|
||||
TrashSizes.fileNameWidth + TrashSizes.lashModifyWidth + TrashSizes.createTimeWidth + TrashSizes.padding;
|
||||
}
|
||||
|
@ -1,12 +1,10 @@
|
||||
import 'package:app_flowy/workspace/presentation/widgets/menu/widget/app/header.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:app_flowy/startup/startup.dart';
|
||||
import 'package:app_flowy/workspace/application/app/app_bloc.dart';
|
||||
import 'package:app_flowy/workspace/application/app/app_listen_bloc.dart';
|
||||
import 'package:app_flowy/workspace/presentation/widgets/menu/menu.dart';
|
||||
import 'package:provider/provider.dart';
|
||||
import 'package:styled_widget/styled_widget.dart';
|
||||
@ -68,36 +66,13 @@ class MenuApp extends MenuItem {
|
||||
appBloc.add(const AppEvent.initial());
|
||||
return appBloc;
|
||||
}),
|
||||
BlocProvider<AppListenBloc>(create: (context) {
|
||||
final listener = getIt<AppListenBloc>(param1: appCtx.app.id);
|
||||
listener.add(const AppListenEvent.started());
|
||||
return listener;
|
||||
}),
|
||||
],
|
||||
child: MultiBlocListener(
|
||||
listeners: [
|
||||
BlocListener<AppListenBloc, AppListenState>(
|
||||
listenWhen: (p, c) => p != c,
|
||||
listener: (context, state) => state.map(
|
||||
initial: (_) => {},
|
||||
didReceiveViews: (state) => appCtx.viewList.items = state.views,
|
||||
loadFail: (s) => appCtx.viewList.items = [],
|
||||
),
|
||||
),
|
||||
],
|
||||
child: BlocBuilder<AppListenBloc, AppListenState>(
|
||||
builder: (context, state) {
|
||||
final child = state.map(
|
||||
initial: (_) => BlocBuilder<AppBloc, AppState>(builder: (context, state) {
|
||||
appCtx.viewList.items = state.views ?? List.empty(growable: false);
|
||||
return _renderViewSection(appCtx.viewList);
|
||||
}),
|
||||
didReceiveViews: (state) => _renderViewSection(appCtx.viewList),
|
||||
loadFail: (s) => FlowyErrorPage(s.error.toString()),
|
||||
);
|
||||
return expandableWrapper(context, child);
|
||||
},
|
||||
),
|
||||
child: BlocBuilder<AppBloc, AppState>(
|
||||
builder: (context, state) {
|
||||
appCtx.viewList.items = state.views ?? List.empty(growable: false);
|
||||
final child = _renderViewSection(appCtx.viewList);
|
||||
return expandableWrapper(context, child);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
@ -23,12 +23,10 @@ class StyledSingleChildScrollView extends StatefulWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
_StyledSingleChildScrollViewState createState() =>
|
||||
_StyledSingleChildScrollViewState();
|
||||
_StyledSingleChildScrollViewState createState() => _StyledSingleChildScrollViewState();
|
||||
}
|
||||
|
||||
class _StyledSingleChildScrollViewState
|
||||
extends State<StyledSingleChildScrollView> {
|
||||
class _StyledSingleChildScrollViewState extends State<StyledSingleChildScrollView> {
|
||||
late ScrollController scrollController;
|
||||
|
||||
@override
|
||||
|
Loading…
Reference in New Issue
Block a user