[flutter]: restore the doc page from banner

This commit is contained in:
appflowy 2021-10-31 19:48:20 +08:00
parent 0606cd4ce9
commit ddfe985065
5 changed files with 346 additions and 14 deletions

View File

@ -1,6 +1,8 @@
import 'dart:convert'; import 'dart:convert';
import 'package:app_flowy/workspace/domain/i_trash.dart';
import 'package:app_flowy/workspace/domain/i_view.dart'; import 'package:app_flowy/workspace/domain/i_view.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/flutter_quill.dart';
import 'package:flowy_log/flowy_log.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/errors.pb.dart';
@ -12,12 +14,19 @@ import 'dart:async';
part 'doc_bloc.freezed.dart'; part 'doc_bloc.freezed.dart';
class DocBloc extends Bloc<DocEvent, DocState> { class DocBloc extends Bloc<DocEvent, DocState> {
final View view;
final IDoc docManager; final IDoc docManager;
final IViewListener listener; final IViewListener listener;
final ITrash trasnManager;
late Document document; late Document document;
late StreamSubscription _subscription; late StreamSubscription _subscription;
DocBloc({required this.docManager, required this.listener}) : super(DocState.initial()); DocBloc({
required this.view,
required this.docManager,
required this.listener,
required this.trasnManager,
}) : super(DocState.initial());
@override @override
Stream<DocState> mapEventToState(DocEvent event) async* { Stream<DocState> mapEventToState(DocEvent event) async* {
@ -29,6 +38,17 @@ class DocBloc extends Bloc<DocEvent, DocState> {
restore: (Restore value) async* { restore: (Restore value) async* {
yield state.copyWith(isDeleted: false); yield state.copyWith(isDeleted: false);
}, },
deletePermanently: (DeletePermanently value) async* {
// final result = await trasnManager.deleteViews([e.trash]);
// yield* _handleResult(result);
yield state;
},
restorePage: (RestorePage value) async* {
final result = await trasnManager.putback(view.id);
yield result.fold((l) => state.copyWith(isDeleted: false), (r) {
return state;
});
},
); );
} }
@ -107,6 +127,8 @@ class DocEvent with _$DocEvent {
const factory DocEvent.initial() = Initial; const factory DocEvent.initial() = Initial;
const factory DocEvent.deleted() = Deleted; const factory DocEvent.deleted() = Deleted;
const factory DocEvent.restore() = Restore; const factory DocEvent.restore() = Restore;
const factory DocEvent.restorePage() = RestorePage;
const factory DocEvent.deletePermanently() = DeletePermanently;
} }
@freezed @freezed

View File

@ -27,6 +27,14 @@ class _$DocEventTearOff {
Restore restore() { Restore restore() {
return const Restore(); return const Restore();
} }
RestorePage restorePage() {
return const RestorePage();
}
DeletePermanently deletePermanently() {
return const DeletePermanently();
}
} }
/// @nodoc /// @nodoc
@ -39,6 +47,8 @@ mixin _$DocEvent {
required TResult Function() initial, required TResult Function() initial,
required TResult Function() deleted, required TResult Function() deleted,
required TResult Function() restore, required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@ -46,6 +56,8 @@ mixin _$DocEvent {
TResult Function()? initial, TResult Function()? initial,
TResult Function()? deleted, TResult Function()? deleted,
TResult Function()? restore, TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@ -54,6 +66,8 @@ mixin _$DocEvent {
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted, required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore, required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@optionalTypeArgs @optionalTypeArgs
@ -61,6 +75,8 @@ mixin _$DocEvent {
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted, TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore, TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@ -121,6 +137,8 @@ class _$Initial implements Initial {
required TResult Function() initial, required TResult Function() initial,
required TResult Function() deleted, required TResult Function() deleted,
required TResult Function() restore, required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) { }) {
return initial(); return initial();
} }
@ -131,6 +149,8 @@ class _$Initial implements Initial {
TResult Function()? initial, TResult Function()? initial,
TResult Function()? deleted, TResult Function()? deleted,
TResult Function()? restore, TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (initial != null) { if (initial != null) {
@ -145,6 +165,8 @@ class _$Initial implements Initial {
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted, required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore, required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) { }) {
return initial(this); return initial(this);
} }
@ -155,6 +177,8 @@ class _$Initial implements Initial {
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted, TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore, TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (initial != null) { if (initial != null) {
@ -208,6 +232,8 @@ class _$Deleted implements Deleted {
required TResult Function() initial, required TResult Function() initial,
required TResult Function() deleted, required TResult Function() deleted,
required TResult Function() restore, required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) { }) {
return deleted(); return deleted();
} }
@ -218,6 +244,8 @@ class _$Deleted implements Deleted {
TResult Function()? initial, TResult Function()? initial,
TResult Function()? deleted, TResult Function()? deleted,
TResult Function()? restore, TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (deleted != null) { if (deleted != null) {
@ -232,6 +260,8 @@ class _$Deleted implements Deleted {
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted, required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore, required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) { }) {
return deleted(this); return deleted(this);
} }
@ -242,6 +272,8 @@ class _$Deleted implements Deleted {
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted, TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore, TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (deleted != null) { if (deleted != null) {
@ -295,6 +327,8 @@ class _$Restore implements Restore {
required TResult Function() initial, required TResult Function() initial,
required TResult Function() deleted, required TResult Function() deleted,
required TResult Function() restore, required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) { }) {
return restore(); return restore();
} }
@ -305,6 +339,8 @@ class _$Restore implements Restore {
TResult Function()? initial, TResult Function()? initial,
TResult Function()? deleted, TResult Function()? deleted,
TResult Function()? restore, TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (restore != null) { if (restore != null) {
@ -319,6 +355,8 @@ class _$Restore implements Restore {
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted, required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore, required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) { }) {
return restore(this); return restore(this);
} }
@ -329,6 +367,8 @@ class _$Restore implements Restore {
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted, TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore, TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(), required TResult orElse(),
}) { }) {
if (restore != null) { if (restore != null) {
@ -342,6 +382,200 @@ abstract class Restore implements DocEvent {
const factory Restore() = _$Restore; const factory Restore() = _$Restore;
} }
/// @nodoc
abstract class $RestorePageCopyWith<$Res> {
factory $RestorePageCopyWith(
RestorePage value, $Res Function(RestorePage) then) =
_$RestorePageCopyWithImpl<$Res>;
}
/// @nodoc
class _$RestorePageCopyWithImpl<$Res> extends _$DocEventCopyWithImpl<$Res>
implements $RestorePageCopyWith<$Res> {
_$RestorePageCopyWithImpl(
RestorePage _value, $Res Function(RestorePage) _then)
: super(_value, (v) => _then(v as RestorePage));
@override
RestorePage get _value => super._value as RestorePage;
}
/// @nodoc
class _$RestorePage implements RestorePage {
const _$RestorePage();
@override
String toString() {
return 'DocEvent.restorePage()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is RestorePage);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() deleted,
required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) {
return restorePage();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? deleted,
TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(),
}) {
if (restorePage != null) {
return restorePage();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) {
return restorePage(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(),
}) {
if (restorePage != null) {
return restorePage(this);
}
return orElse();
}
}
abstract class RestorePage implements DocEvent {
const factory RestorePage() = _$RestorePage;
}
/// @nodoc
abstract class $DeletePermanentlyCopyWith<$Res> {
factory $DeletePermanentlyCopyWith(
DeletePermanently value, $Res Function(DeletePermanently) then) =
_$DeletePermanentlyCopyWithImpl<$Res>;
}
/// @nodoc
class _$DeletePermanentlyCopyWithImpl<$Res> extends _$DocEventCopyWithImpl<$Res>
implements $DeletePermanentlyCopyWith<$Res> {
_$DeletePermanentlyCopyWithImpl(
DeletePermanently _value, $Res Function(DeletePermanently) _then)
: super(_value, (v) => _then(v as DeletePermanently));
@override
DeletePermanently get _value => super._value as DeletePermanently;
}
/// @nodoc
class _$DeletePermanently implements DeletePermanently {
const _$DeletePermanently();
@override
String toString() {
return 'DocEvent.deletePermanently()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is DeletePermanently);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function() deleted,
required TResult Function() restore,
required TResult Function() restorePage,
required TResult Function() deletePermanently,
}) {
return deletePermanently();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function()? deleted,
TResult Function()? restore,
TResult Function()? restorePage,
TResult Function()? deletePermanently,
required TResult orElse(),
}) {
if (deletePermanently != null) {
return deletePermanently();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(Deleted value) deleted,
required TResult Function(Restore value) restore,
required TResult Function(RestorePage value) restorePage,
required TResult Function(DeletePermanently value) deletePermanently,
}) {
return deletePermanently(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(Deleted value)? deleted,
TResult Function(Restore value)? restore,
TResult Function(RestorePage value)? restorePage,
TResult Function(DeletePermanently value)? deletePermanently,
required TResult orElse(),
}) {
if (deletePermanently != null) {
return deletePermanently(this);
}
return orElse();
}
}
abstract class DeletePermanently implements DocEvent {
const factory DeletePermanently() = _$DeletePermanently;
}
/// @nodoc /// @nodoc
class _$DocStateTearOff { class _$DocStateTearOff {
const _$DocStateTearOff(); const _$DocStateTearOff();

View File

@ -89,8 +89,10 @@ class HomeDepsResolver {
// Doc // Doc
getIt.registerFactoryParam<DocBloc, View, void>( getIt.registerFactoryParam<DocBloc, View, void>(
(view, _) => DocBloc( (view, _) => DocBloc(
view: view,
docManager: getIt<IDoc>(param1: view.id), docManager: getIt<IDoc>(param1: view.id),
listener: getIt<IViewListener>(param1: view), listener: getIt<IViewListener>(param1: view),
trasnManager: getIt<ITrash>(),
), ),
); );

View File

@ -2,7 +2,7 @@ import 'package:app_flowy/startup/startup.dart';
import 'package:app_flowy/workspace/application/doc/doc_bloc.dart'; import 'package:app_flowy/workspace/application/doc/doc_bloc.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_scroll_bar.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter_quill/flutter_quill.dart'; import 'package:flutter_quill/flutter_quill.dart' as quill;
import 'package:flowy_infra_ui/style_widget/progress_indicator.dart'; import 'package:flowy_infra_ui/style_widget/progress_indicator.dart';
import 'package:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -10,6 +10,7 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'styles.dart'; import 'styles.dart';
import 'widget/banner.dart';
import 'widget/toolbar/tool_bar.dart'; import 'widget/toolbar/tool_bar.dart';
class DocPage extends StatefulWidget { class DocPage extends StatefulWidget {
@ -42,7 +43,7 @@ class _DocPageState extends State<DocPage> {
return state.loadState.map( return state.loadState.map(
loading: (_) => const FlowyProgressIndicator(), loading: (_) => const FlowyProgressIndicator(),
finish: (result) => result.successOrFail.fold( finish: (result) => result.successOrFail.fold(
(_) => _renderDoc(context), (_) => _renderDoc(context, state),
(err) => FlowyErrorPage(err.toString()), (err) => FlowyErrorPage(err.toString()),
), ),
); );
@ -56,12 +57,16 @@ class _DocPageState extends State<DocPage> {
super.dispose(); super.dispose();
} }
Widget _renderDoc(BuildContext context) { Widget _renderDoc(BuildContext context, DocState state) {
QuillController controller = QuillController( quill.QuillController controller = quill.QuillController(
document: context.read<DocBloc>().document, document: context.read<DocBloc>().document,
selection: const TextSelection.collapsed(offset: 0), selection: const TextSelection.collapsed(offset: 0),
); );
return Column( return Column(
children: [
if (state.isDeleted) _renderBanner(context),
Expanded(
child: Column(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
_renderEditor(controller), _renderEditor(controller),
@ -69,11 +74,25 @@ class _DocPageState extends State<DocPage> {
_renderToolbar(controller), _renderToolbar(controller),
const VSpace(10), const VSpace(10),
], ],
).padding(horizontal: 40, top: 28); ).padding(horizontal: 40, top: 28),
),
],
);
} }
Widget _renderEditor(QuillController controller) { Widget _renderBanner(BuildContext context) {
final editor = QuillEditor( return DocBanner(
onRestore: () {
context.read<DocBloc>().add(const DocEvent.restorePage());
},
onDelete: () {
context.read<DocBloc>().add(const DocEvent.deletePermanently());
},
);
}
Widget _renderEditor(quill.QuillController controller) {
final editor = quill.QuillEditor(
controller: controller, controller: controller,
focusNode: _focusNode, focusNode: _focusNode,
scrollable: true, scrollable: true,
@ -96,7 +115,7 @@ class _DocPageState extends State<DocPage> {
); );
} }
Widget _renderToolbar(QuillController controller) { Widget _renderToolbar(quill.QuillController controller) {
return EditorToolbar.basic( return EditorToolbar.basic(
controller: controller, controller: controller,
); );

View File

@ -0,0 +1,55 @@
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/widget/buttons/base_styled_button.dart';
import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
class DocBanner extends StatelessWidget {
final void Function() onRestore;
final void Function() onDelete;
const DocBanner({required this.onRestore, required this.onDelete, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
// [[Row]] CrossAxisAlignment vs mainAxisAlignment
// https://stackoverflow.com/questions/53850149/flutter-crossaxisalignment-vs-mainaxisalignment
return Container(
color: theme.main1,
height: 60,
child: Row(
children: [
const FlowyText.medium('This page is in Trash', color: Colors.white),
const HSpace(20),
BaseStyledButton(
minWidth: 160,
minHeight: 40,
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
hoverColor: theme.main2,
downColor: theme.main1,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
child: const FlowyText.medium('Restore page', color: Colors.white, fontSize: 14),
onPressed: onRestore),
const HSpace(20),
BaseStyledButton(
minWidth: 220,
minHeight: 40,
contentPadding: EdgeInsets.zero,
bgColor: Colors.transparent,
hoverColor: theme.main2,
downColor: theme.main1,
outlineColor: Colors.white,
borderRadius: Corners.s8Border,
child: const FlowyText.medium('Delete permanently', color: Colors.white, fontSize: 14),
onPressed: onDelete),
],
crossAxisAlignment: CrossAxisAlignment.center,
mainAxisAlignment: MainAxisAlignment.center,
),
);
}
}