[flutter]: add restore & delete all api

This commit is contained in:
appflowy 2021-10-18 16:30:20 +08:00
parent 315c8b107a
commit 4f0f4221fc
14 changed files with 99 additions and 786 deletions

View File

@ -9,9 +9,9 @@ import 'package:dartz/dartz.dart';
part 'app_bloc.freezed.dart'; part 'app_bloc.freezed.dart';
class AppBloc extends Bloc<AppEvent, AppState> { class AppBloc extends Bloc<AppEvent, AppState> {
final IApp iAppImpl; final IApp appManager;
final IAppListenr listener; final IAppListenr listener;
AppBloc({required this.iAppImpl, required this.listener}) : super(AppState.initial()); AppBloc({required this.appManager, required this.listener}) : super(AppState.initial());
@override @override
Stream<AppState> mapEventToState( Stream<AppState> mapEventToState(
@ -24,7 +24,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
yield* _fetchViews(); yield* _fetchViews();
}, },
createView: (CreateView value) async* { createView: (CreateView value) async* {
final viewOrFailed = await iAppImpl.createView(name: value.name, desc: value.desc, viewType: value.viewType); final viewOrFailed = await appManager.createView(name: value.name, desc: value.desc, viewType: value.viewType);
yield viewOrFailed.fold((view) => state, (error) { yield viewOrFailed.fold((view) => state, (error) {
Log.error(error); Log.error(error);
return state.copyWith(successOrFailure: right(error)); return state.copyWith(successOrFailure: right(error));
@ -52,7 +52,7 @@ class AppBloc extends Bloc<AppEvent, AppState> {
} }
Stream<AppState> _fetchViews() async* { Stream<AppState> _fetchViews() async* {
final viewsOrFailed = await iAppImpl.getViews(); final viewsOrFailed = await appManager.getViews();
yield viewsOrFailed.fold( yield viewsOrFailed.fold(
(apps) => state.copyWith(views: apps), (apps) => state.copyWith(views: apps),
(error) { (error) {

View File

@ -1,62 +0,0 @@
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';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:dartz/dartz.dart';
part 'app_listen_bloc.freezed.dart';
class AppListenBloc extends Bloc<AppListenEvent, AppListenState> {
final IAppListenr listener;
AppListenBloc(this.listener) : super(const AppListenState.initial());
@override
Stream<AppListenState> mapEventToState(
AppListenEvent event,
) async* {
yield* event.map(started: (_) async* {
listener.start(
viewsChangeCallback: (viewsOrFail) => _handleViewsOrFail(viewsOrFail),
);
}, didReceiveViews: (ViewsReceived value) async* {
yield value.viewsOrFail.fold(
(views) => AppListenState.didReceiveViews(views),
(error) => AppListenState.loadFail(error),
);
});
}
void _handleViewsOrFail(Either<List<View>, WorkspaceError> viewsOrFail) {
viewsOrFail.fold(
(views) => add(AppListenEvent.didReceiveViews(left(views))),
(error) => add(AppListenEvent.didReceiveViews(right(error))),
);
}
@override
Future<void> close() async {
await listener.stop();
return super.close();
}
}
@freezed
class AppListenEvent with _$AppListenEvent {
const factory AppListenEvent.started() = _Started;
const factory AppListenEvent.didReceiveViews(Either<List<View>, WorkspaceError> viewsOrFail) = ViewsReceived;
}
@freezed
class AppListenState with _$AppListenState {
const factory AppListenState.initial() = _Initial;
const factory AppListenState.didReceiveViews(
List<View> views,
) = _LoadViews;
const factory AppListenState.loadFail(
WorkspaceError error,
) = _LoadFail;
}

View File

@ -1,684 +0,0 @@
// GENERATED CODE - DO NOT MODIFY BY HAND
// ignore_for_file: unused_element, deprecated_member_use, deprecated_member_use_from_same_package, use_function_type_syntax_for_parameters, unnecessary_const, avoid_init_to_null, invalid_override_different_default_values_named, prefer_expression_function_bodies, annotate_overrides, invalid_annotation_target
part of 'app_listen_bloc.dart';
// **************************************************************************
// FreezedGenerator
// **************************************************************************
T _$identity<T>(T value) => value;
final _privateConstructorUsedError = UnsupportedError(
'It seems like you constructed your class using `MyClass._()`. This constructor is only meant to be used by freezed and you are not supposed to need it nor use it.\nPlease check the documentation here for more informations: https://github.com/rrousselGit/freezed#custom-getters-and-methods');
/// @nodoc
class _$AppListenEventTearOff {
const _$AppListenEventTearOff();
_Started started() {
return const _Started();
}
ViewsReceived didReceiveViews(
Either<List<View>, WorkspaceError> viewsOrFail) {
return ViewsReceived(
viewsOrFail,
);
}
}
/// @nodoc
const $AppListenEvent = _$AppListenEventTearOff();
/// @nodoc
mixin _$AppListenEvent {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
didReceiveViews,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
didReceiveViews,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) didReceiveViews,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AppListenEventCopyWith<$Res> {
factory $AppListenEventCopyWith(
AppListenEvent value, $Res Function(AppListenEvent) then) =
_$AppListenEventCopyWithImpl<$Res>;
}
/// @nodoc
class _$AppListenEventCopyWithImpl<$Res>
implements $AppListenEventCopyWith<$Res> {
_$AppListenEventCopyWithImpl(this._value, this._then);
final AppListenEvent _value;
// ignore: unused_field
final $Res Function(AppListenEvent) _then;
}
/// @nodoc
abstract class _$StartedCopyWith<$Res> {
factory _$StartedCopyWith(_Started value, $Res Function(_Started) then) =
__$StartedCopyWithImpl<$Res>;
}
/// @nodoc
class __$StartedCopyWithImpl<$Res> extends _$AppListenEventCopyWithImpl<$Res>
implements _$StartedCopyWith<$Res> {
__$StartedCopyWithImpl(_Started _value, $Res Function(_Started) _then)
: super(_value, (v) => _then(v as _Started));
@override
_Started get _value => super._value as _Started;
}
/// @nodoc
class _$_Started implements _Started {
const _$_Started();
@override
String toString() {
return 'AppListenEvent.started()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Started);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
didReceiveViews,
}) {
return started();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
didReceiveViews,
required TResult orElse(),
}) {
if (started != null) {
return started();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) didReceiveViews,
}) {
return started(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) {
if (started != null) {
return started(this);
}
return orElse();
}
}
abstract class _Started implements AppListenEvent {
const factory _Started() = _$_Started;
}
/// @nodoc
abstract class $ViewsReceivedCopyWith<$Res> {
factory $ViewsReceivedCopyWith(
ViewsReceived value, $Res Function(ViewsReceived) then) =
_$ViewsReceivedCopyWithImpl<$Res>;
$Res call({Either<List<View>, WorkspaceError> viewsOrFail});
}
/// @nodoc
class _$ViewsReceivedCopyWithImpl<$Res>
extends _$AppListenEventCopyWithImpl<$Res>
implements $ViewsReceivedCopyWith<$Res> {
_$ViewsReceivedCopyWithImpl(
ViewsReceived _value, $Res Function(ViewsReceived) _then)
: super(_value, (v) => _then(v as ViewsReceived));
@override
ViewsReceived get _value => super._value as ViewsReceived;
@override
$Res call({
Object? viewsOrFail = freezed,
}) {
return _then(ViewsReceived(
viewsOrFail == freezed
? _value.viewsOrFail
: viewsOrFail // ignore: cast_nullable_to_non_nullable
as Either<List<View>, WorkspaceError>,
));
}
}
/// @nodoc
class _$ViewsReceived implements ViewsReceived {
const _$ViewsReceived(this.viewsOrFail);
@override
final Either<List<View>, WorkspaceError> viewsOrFail;
@override
String toString() {
return 'AppListenEvent.didReceiveViews(viewsOrFail: $viewsOrFail)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is ViewsReceived &&
(identical(other.viewsOrFail, viewsOrFail) ||
const DeepCollectionEquality()
.equals(other.viewsOrFail, viewsOrFail)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(viewsOrFail);
@JsonKey(ignore: true)
@override
$ViewsReceivedCopyWith<ViewsReceived> get copyWith =>
_$ViewsReceivedCopyWithImpl<ViewsReceived>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() started,
required TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)
didReceiveViews,
}) {
return didReceiveViews(viewsOrFail);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? started,
TResult Function(Either<List<View>, WorkspaceError> viewsOrFail)?
didReceiveViews,
required TResult orElse(),
}) {
if (didReceiveViews != null) {
return didReceiveViews(viewsOrFail);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Started value) started,
required TResult Function(ViewsReceived value) didReceiveViews,
}) {
return didReceiveViews(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Started value)? started,
TResult Function(ViewsReceived value)? didReceiveViews,
required TResult orElse(),
}) {
if (didReceiveViews != null) {
return didReceiveViews(this);
}
return orElse();
}
}
abstract class ViewsReceived implements AppListenEvent {
const factory ViewsReceived(Either<List<View>, WorkspaceError> viewsOrFail) =
_$ViewsReceived;
Either<List<View>, WorkspaceError> get viewsOrFail =>
throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$ViewsReceivedCopyWith<ViewsReceived> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
class _$AppListenStateTearOff {
const _$AppListenStateTearOff();
_Initial initial() {
return const _Initial();
}
_LoadViews didReceiveViews(List<View> views) {
return _LoadViews(
views,
);
}
_LoadFail loadFail(WorkspaceError error) {
return _LoadFail(
error,
);
}
}
/// @nodoc
const $AppListenState = _$AppListenStateTearOff();
/// @nodoc
mixin _$AppListenState {
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) =>
throw _privateConstructorUsedError;
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class $AppListenStateCopyWith<$Res> {
factory $AppListenStateCopyWith(
AppListenState value, $Res Function(AppListenState) then) =
_$AppListenStateCopyWithImpl<$Res>;
}
/// @nodoc
class _$AppListenStateCopyWithImpl<$Res>
implements $AppListenStateCopyWith<$Res> {
_$AppListenStateCopyWithImpl(this._value, this._then);
final AppListenState _value;
// ignore: unused_field
final $Res Function(AppListenState) _then;
}
/// @nodoc
abstract class _$InitialCopyWith<$Res> {
factory _$InitialCopyWith(_Initial value, $Res Function(_Initial) then) =
__$InitialCopyWithImpl<$Res>;
}
/// @nodoc
class __$InitialCopyWithImpl<$Res> extends _$AppListenStateCopyWithImpl<$Res>
implements _$InitialCopyWith<$Res> {
__$InitialCopyWithImpl(_Initial _value, $Res Function(_Initial) _then)
: super(_value, (v) => _then(v as _Initial));
@override
_Initial get _value => super._value as _Initial;
}
/// @nodoc
class _$_Initial implements _Initial {
const _$_Initial();
@override
String toString() {
return 'AppListenState.initial()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is _Initial);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return initial();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) {
if (initial != null) {
return initial();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return initial(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {
if (initial != null) {
return initial(this);
}
return orElse();
}
}
abstract class _Initial implements AppListenState {
const factory _Initial() = _$_Initial;
}
/// @nodoc
abstract class _$LoadViewsCopyWith<$Res> {
factory _$LoadViewsCopyWith(
_LoadViews value, $Res Function(_LoadViews) then) =
__$LoadViewsCopyWithImpl<$Res>;
$Res call({List<View> views});
}
/// @nodoc
class __$LoadViewsCopyWithImpl<$Res> extends _$AppListenStateCopyWithImpl<$Res>
implements _$LoadViewsCopyWith<$Res> {
__$LoadViewsCopyWithImpl(_LoadViews _value, $Res Function(_LoadViews) _then)
: super(_value, (v) => _then(v as _LoadViews));
@override
_LoadViews get _value => super._value as _LoadViews;
@override
$Res call({
Object? views = freezed,
}) {
return _then(_LoadViews(
views == freezed
? _value.views
: views // ignore: cast_nullable_to_non_nullable
as List<View>,
));
}
}
/// @nodoc
class _$_LoadViews implements _LoadViews {
const _$_LoadViews(this.views);
@override
final List<View> views;
@override
String toString() {
return 'AppListenState.didReceiveViews(views: $views)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _LoadViews &&
(identical(other.views, views) ||
const DeepCollectionEquality().equals(other.views, views)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(views);
@JsonKey(ignore: true)
@override
_$LoadViewsCopyWith<_LoadViews> get copyWith =>
__$LoadViewsCopyWithImpl<_LoadViews>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return didReceiveViews(views);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
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(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return didReceiveViews(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {
if (didReceiveViews != null) {
return didReceiveViews(this);
}
return orElse();
}
}
abstract class _LoadViews implements AppListenState {
const factory _LoadViews(List<View> views) = _$_LoadViews;
List<View> get views => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
_$LoadViewsCopyWith<_LoadViews> get copyWith =>
throw _privateConstructorUsedError;
}
/// @nodoc
abstract class _$LoadFailCopyWith<$Res> {
factory _$LoadFailCopyWith(_LoadFail value, $Res Function(_LoadFail) then) =
__$LoadFailCopyWithImpl<$Res>;
$Res call({WorkspaceError error});
}
/// @nodoc
class __$LoadFailCopyWithImpl<$Res> extends _$AppListenStateCopyWithImpl<$Res>
implements _$LoadFailCopyWith<$Res> {
__$LoadFailCopyWithImpl(_LoadFail _value, $Res Function(_LoadFail) _then)
: super(_value, (v) => _then(v as _LoadFail));
@override
_LoadFail get _value => super._value as _LoadFail;
@override
$Res call({
Object? error = freezed,
}) {
return _then(_LoadFail(
error == freezed
? _value.error
: error // ignore: cast_nullable_to_non_nullable
as WorkspaceError,
));
}
}
/// @nodoc
class _$_LoadFail implements _LoadFail {
const _$_LoadFail(this.error);
@override
final WorkspaceError error;
@override
String toString() {
return 'AppListenState.loadFail(error: $error)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is _LoadFail &&
(identical(other.error, error) ||
const DeepCollectionEquality().equals(other.error, error)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(error);
@JsonKey(ignore: true)
@override
_$LoadFailCopyWith<_LoadFail> get copyWith =>
__$LoadFailCopyWithImpl<_LoadFail>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(List<View> views) didReceiveViews,
required TResult Function(WorkspaceError error) loadFail,
}) {
return loadFail(error);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(List<View> views)? didReceiveViews,
TResult Function(WorkspaceError error)? loadFail,
required TResult orElse(),
}) {
if (loadFail != null) {
return loadFail(error);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(_Initial value) initial,
required TResult Function(_LoadViews value) didReceiveViews,
required TResult Function(_LoadFail value) loadFail,
}) {
return loadFail(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(_Initial value)? initial,
TResult Function(_LoadViews value)? didReceiveViews,
TResult Function(_LoadFail value)? loadFail,
required TResult orElse(),
}) {
if (loadFail != null) {
return loadFail(this);
}
return orElse();
}
}
abstract class _LoadFail implements AppListenState {
const factory _LoadFail(WorkspaceError error) = _$_LoadFail;
WorkspaceError get error => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
_$LoadFailCopyWith<_LoadFail> get copyWith =>
throw _privateConstructorUsedError;
}

View File

@ -28,20 +28,27 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
}, },
putback: (e) async* { putback: (e) async* {
final result = await iTrash.putback(e.trashId); final result = await iTrash.putback(e.trashId);
yield result.fold( yield* _handleResult(result);
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
);
}, },
delete: (e) async* { delete: (e) async* {
final result = await iTrash.deleteViews([e.trashId]); final result = await iTrash.deleteViews([e.trashId]);
result.fold((l) {}, (error) {}); yield* _handleResult(result);
},
deleteAll: (e) async* {
final result = await iTrash.deleteAll();
yield* _handleResult(result);
}, },
deleteAll: (e) async* {},
restoreAll: (e) async* {}, restoreAll: (e) async* {},
); );
} }
Stream<TrashState> _handleResult(Either<dynamic, WorkspaceError> result) async* {
yield result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
);
}
void _listenTrashUpdated(Either<List<Trash>, WorkspaceError> trashOrFailed) { void _listenTrashUpdated(Either<List<Trash>, WorkspaceError> trashOrFailed) {
trashOrFailed.fold( trashOrFailed.fold(
(trash) { (trash) {

View File

@ -9,6 +9,10 @@ abstract class ITrash {
Future<Either<Unit, WorkspaceError>> putback(String trashId); Future<Either<Unit, WorkspaceError>> putback(String trashId);
Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds); Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds);
Future<Either<Unit, WorkspaceError>> restoreAll();
Future<Either<Unit, WorkspaceError>> deleteAll();
} }
typedef TrashUpdatedCallback = void Function(Either<List<Trash>, WorkspaceError> trashOrFailed); typedef TrashUpdatedCallback = void Function(Either<List<Trash>, WorkspaceError> trashOrFailed);

View File

@ -1,5 +1,4 @@
import 'package:app_flowy/workspace/application/app/app_bloc.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/application/doc/doc_bloc.dart'; import 'package:app_flowy/workspace/application/doc/doc_bloc.dart';
import 'package:app_flowy/workspace/application/doc/doc_edit_bloc.dart'; import 'package:app_flowy/workspace/application/doc/doc_edit_bloc.dart';
import 'package:app_flowy/workspace/application/menu/menu_bloc.dart'; import 'package:app_flowy/workspace/application/menu/menu_bloc.dart';
@ -56,7 +55,7 @@ class HomeDepsResolver {
(view, _) => IViewListenerImpl(repo: ViewListenerRepository(view: view))); (view, _) => IViewListenerImpl(repo: ViewListenerRepository(view: view)));
getIt.registerFactoryParam<ViewBloc, View, void>( getIt.registerFactoryParam<ViewBloc, View, void>(
(view, _) => ViewBloc( (view, _) => ViewBloc(
iViewImpl: getIt<IView>(param1: view), viewManager: getIt<IView>(param1: view),
listener: getIt<IViewListener>(param1: view), listener: getIt<IViewListener>(param1: view),
), ),
); );
@ -80,12 +79,10 @@ class HomeDepsResolver {
// App // App
getIt.registerFactoryParam<AppBloc, String, void>( getIt.registerFactoryParam<AppBloc, String, void>(
(appId, _) => AppBloc( (appId, _) => AppBloc(
iAppImpl: getIt<IApp>(param1: appId), appManager: getIt<IApp>(param1: appId),
listener: getIt<IAppListenr>(param1: appId), listener: getIt<IAppListenr>(param1: appId),
), ),
); );
getIt.registerFactoryParam<AppListenBloc, String, void>(
(appId, _) => AppListenBloc(getIt<IAppListenr>(param1: appId)));
// Doc // Doc
getIt.registerFactoryParam<DocBloc, String, void>((docId, _) => DocBloc(iDocImpl: getIt<IDoc>(param1: docId))); getIt.registerFactoryParam<DocBloc, String, void>((docId, _) => DocBloc(iDocImpl: getIt<IDoc>(param1: docId)));
@ -96,6 +93,6 @@ class HomeDepsResolver {
getIt.registerLazySingleton<TrashListenerRepo>(() => TrashListenerRepo()); getIt.registerLazySingleton<TrashListenerRepo>(() => TrashListenerRepo());
getIt.registerFactory<ITrash>(() => ITrashImpl(repo: getIt<TrashRepo>())); getIt.registerFactory<ITrash>(() => ITrashImpl(repo: getIt<TrashRepo>()));
getIt.registerFactory<ITrashListener>(() => ITrashListenerImpl(repo: getIt<TrashListenerRepo>())); getIt.registerFactory<ITrashListener>(() => ITrashListenerImpl(repo: getIt<TrashListenerRepo>()));
getIt.registerFactory<TrashBloc>(() => TrashBloc(iTrash: getIt<ITrash>(), listener: getIt<ITrashListener>())); getIt.registerFactory<TrashBloc>(() => TrashBloc(trasnManager: getIt<ITrash>(), listener: getIt<ITrashListener>()));
} }
} }

View File

@ -28,6 +28,16 @@ class ITrashImpl implements ITrash {
Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds) { Future<Either<Unit, WorkspaceError>> deleteViews(List<String> trashIds) {
return repo.deleteViews(trashIds); return repo.deleteViews(trashIds);
} }
@override
Future<Either<Unit, WorkspaceError>> deleteAll() {
return repo.deleteAll();
}
@override
Future<Either<Unit, WorkspaceError>> restoreAll() {
return repo.restoreAll();
}
} }
class ITrashListenerImpl extends ITrashListener { class ITrashListenerImpl extends ITrashListener {

View File

@ -29,6 +29,14 @@ class TrashRepo {
return WorkspaceEventDeleteTrash(trashIdentifiers).send(); return WorkspaceEventDeleteTrash(trashIdentifiers).send();
} }
Future<Either<Unit, WorkspaceError>> restoreAll() {
return WorkspaceEventRestoreAll().send();
}
Future<Either<Unit, WorkspaceError>> deleteAll() {
return WorkspaceEventDeleteAll().send();
}
} }
class TrashListenerRepo { class TrashListenerRepo {

View File

@ -53,6 +53,15 @@ pub struct TrashIdentifier {
pub ty: TrashType, pub ty: TrashType,
} }
impl std::convert::From<&Trash> for TrashIdentifier {
fn from(trash: &Trash) -> Self {
TrashIdentifier {
id: trash.id.clone(),
ty: trash.ty.clone(),
}
}
}
#[derive(PartialEq, ProtoBuf, Default, Debug, Clone)] #[derive(PartialEq, ProtoBuf, Default, Debug, Clone)]
pub struct Trash { pub struct Trash {
#[pb(index = 1)] #[pb(index = 1)]

View File

@ -23,7 +23,7 @@ macro_rules! impl_def_and_def_mut {
impl $target { impl $target {
#[allow(dead_code)] #[allow(dead_code)]
pub fn take_items(&mut self) -> Vec<$item> { ::std::mem::replace(&mut self.items, vec![]) } pub fn into_inner(&mut self) -> Vec<$item> { ::std::mem::replace(&mut self.items, vec![]) }
#[allow(dead_code)] #[allow(dead_code)]
pub fn push(&mut self, item: $item) { pub fn push(&mut self, item: $item) {

View File

@ -42,7 +42,7 @@ impl TrashCan {
pub fn trash_ids(&self, conn: &SqliteConnection) -> Result<Vec<String>, WorkspaceError> { pub fn trash_ids(&self, conn: &SqliteConnection) -> Result<Vec<String>, WorkspaceError> {
let ids = TrashTableSql::read_all(&*conn)? let ids = TrashTableSql::read_all(&*conn)?
.take_items() .into_inner()
.into_iter() .into_iter()
.map(|item| item.id) .map(|item| item.id)
.collect::<Vec<String>>(); .collect::<Vec<String>>();
@ -113,20 +113,16 @@ impl TrashCan {
#[tracing::instrument(level = "debug", skip(self, trash), err)] #[tracing::instrument(level = "debug", skip(self, trash), err)]
pub async fn add<T: Into<Trash>>(&self, trash: Vec<T>) -> Result<(), WorkspaceError> { pub async fn add<T: Into<Trash>>(&self, trash: Vec<T>) -> Result<(), WorkspaceError> {
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1); let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
let trash = trash.into_iter().map(|t| t.into()).collect::<Vec<Trash>>(); let repeated_trash = trash.into_iter().map(|t| t.into()).collect::<Vec<Trash>>();
let mut items = vec![]; let identifiers = repeated_trash
.iter()
.map(|t| t.into())
.collect::<Vec<TrashIdentifier>>();
let _ = thread::scope(|_s| { let _ = thread::scope(|_s| {
let conn = self.database.db_connection()?; let conn = self.database.db_connection()?;
conn.immediate_transaction::<_, WorkspaceError, _>(|| { conn.immediate_transaction::<_, WorkspaceError, _>(|| {
for t in &trash { let _ = TrashTableSql::create_trash(repeated_trash.clone(), &*conn)?;
log::debug!("create trash: {:?}", t); self.create_trash_on_server(repeated_trash);
items.push(TrashIdentifier {
id: t.id.clone(),
ty: t.ty.clone(),
});
let _ = TrashTableSql::create_trash(t.clone().into(), &*conn)?;
}
self.create_trash_on_server(trash);
notify_trash_num_changed(TrashTableSql::read_all(&conn)?); notify_trash_num_changed(TrashTableSql::read_all(&conn)?);
Ok(()) Ok(())
})?; })?;
@ -134,7 +130,7 @@ impl TrashCan {
}) })
.unwrap()?; .unwrap()?;
let _ = self.notify.send(TrashEvent::NewTrash(items.into(), tx)); let _ = self.notify.send(TrashEvent::NewTrash(identifiers.into(), tx));
let _ = rx.recv().await.unwrap()?; let _ = rx.recv().await.unwrap()?;
Ok(()) Ok(())
@ -185,10 +181,7 @@ impl TrashCan {
match pool.get() { match pool.get() {
Ok(conn) => { Ok(conn) => {
let result = conn.immediate_transaction::<_, WorkspaceError, _>(|| { let result = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
for trash in &repeated_trash.items { TrashTableSql::create_trash(repeated_trash.items.clone(), &*conn)
let _ = TrashTableSql::create_trash(trash.clone().into(), &*conn)?;
}
Ok(())
}); });
match result { match result {
@ -214,7 +207,6 @@ impl TrashCan {
#[tracing::instrument(skip(repeated_trash), fields(trash_count))] #[tracing::instrument(skip(repeated_trash), fields(trash_count))]
fn notify_trash_num_changed(repeated_trash: RepeatedTrash) { fn notify_trash_num_changed(repeated_trash: RepeatedTrash) {
tracing::Span::current().record("trash_count", &repeated_trash.len()); tracing::Span::current().record("trash_count", &repeated_trash.len());
send_anonymous_dart_notification(WorkspaceNotification::TrashUpdated) send_anonymous_dart_notification(WorkspaceNotification::TrashUpdated)
.payload(repeated_trash) .payload(repeated_trash)
.send(); .send();

View File

@ -274,13 +274,13 @@ impl WorkspaceController {
log::debug!("Save {} workspace", workspaces.len()); log::debug!("Save {} workspace", workspaces.len());
for workspace in &workspaces.items { for workspace in &workspaces.items {
let mut m_workspace = workspace.clone(); let mut m_workspace = workspace.clone();
let apps = m_workspace.apps.take_items(); let apps = m_workspace.apps.into_inner();
let workspace_table = WorkspaceTable::new(m_workspace, &user_id); let workspace_table = WorkspaceTable::new(m_workspace, &user_id);
let _ = workspace_sql.create_workspace(workspace_table, &*conn)?; let _ = workspace_sql.create_workspace(workspace_table, &*conn)?;
log::debug!("Save {} apps", apps.len()); log::debug!("Save {} apps", apps.len());
for mut app in apps { for mut app in apps {
let views = app.belongings.take_items(); let views = app.belongings.into_inner();
match app_ctrl.save_app(app, &*conn) { match app_ctrl.save_app(app, &*conn) {
Ok(_) => {}, Ok(_) => {},
Err(e) => log::error!("create app failed: {:?}", e), Err(e) => log::error!("create app failed: {:?}", e),

View File

@ -1,4 +1,8 @@
use crate::{entities::trash::RepeatedTrash, errors::WorkspaceError, sql_tables::trash::TrashTable}; use crate::{
entities::trash::RepeatedTrash,
errors::WorkspaceError,
sql_tables::trash::{TrashTable, TrashTableChangeset},
};
use crate::entities::trash::Trash; use crate::entities::trash::Trash;
use flowy_database::{ use flowy_database::{
@ -10,8 +14,18 @@ use flowy_database::{
pub struct TrashTableSql {} pub struct TrashTableSql {}
impl TrashTableSql { impl TrashTableSql {
pub(crate) fn create_trash(trash_table: TrashTable, conn: &SqliteConnection) -> Result<(), WorkspaceError> { pub(crate) fn create_trash(repeated_trash: Vec<Trash>, conn: &SqliteConnection) -> Result<(), WorkspaceError> {
diesel_insert_table!(trash_table, &trash_table, conn); for trash in repeated_trash {
let trash_table: TrashTable = trash.into();
match diesel_record_count!(trash_table, &trash_table.id, conn) {
0 => diesel_insert_table!(trash_table, &trash_table, conn),
_ => {
let changeset = TrashTableChangeset::from(trash_table);
diesel_update_table!(trash_table, changeset, conn)
},
}
}
Ok(()) Ok(())
} }

View File

@ -37,6 +37,24 @@ impl std::convert::From<Trash> for TrashTable {
} }
} }
#[derive(AsChangeset, Identifiable, Clone, Default, Debug)]
#[table_name = "trash_table"]
pub(crate) struct TrashTableChangeset {
pub id: String,
pub name: Option<String>,
pub modified_time: i64,
}
impl std::convert::From<TrashTable> for TrashTableChangeset {
fn from(trash: TrashTable) -> Self {
TrashTableChangeset {
id: trash.id,
name: Some(trash.name),
modified_time: trash.modified_time,
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)] #[derive(Clone, Copy, PartialEq, Eq, Debug, Hash, FromSqlRow, AsExpression)]
#[repr(i32)] #[repr(i32)]
#[sql_type = "Integer"] #[sql_type = "Integer"]