mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
[client]: fix trash notification issue
This commit is contained in:
parent
560ee376f9
commit
2513853ea4
@ -40,7 +40,7 @@ class ApplicationBlocObserver extends BlocObserver {
|
|||||||
@override
|
@override
|
||||||
// ignore: unnecessary_overrides
|
// ignore: unnecessary_overrides
|
||||||
void onTransition(Bloc bloc, Transition transition) {
|
void onTransition(Bloc bloc, Transition transition) {
|
||||||
// Log.debug("[current]: ${transition.currentState} \n[next]: ${transition.nextState}");
|
Log.debug("[current]: ${transition.currentState} \n[next]: ${transition.nextState}");
|
||||||
super.onTransition(bloc, transition);
|
super.onTransition(bloc, transition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,7 +28,10 @@ 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);
|
||||||
result.fold((l) {}, (error) {});
|
yield result.fold(
|
||||||
|
(l) => state.copyWith(successOrFailure: left(unit)),
|
||||||
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
|
);
|
||||||
},
|
},
|
||||||
delete: (e) async* {
|
delete: (e) async* {
|
||||||
final result = await iTrash.delete(e.trashId);
|
final result = await iTrash.delete(e.trashId);
|
||||||
|
@ -32,7 +32,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
|||||||
(error) => state.copyWith(successOrFailure: right(error)),
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
);
|
);
|
||||||
}, delete: (e) async* {
|
}, delete: (e) async* {
|
||||||
final result = await iViewImpl.pushIntoTrash();
|
final result = await iViewImpl.delete();
|
||||||
yield result.fold(
|
yield result.fold(
|
||||||
(l) => state.copyWith(successOrFailure: left(unit)),
|
(l) => state.copyWith(successOrFailure: left(unit)),
|
||||||
(error) => state.copyWith(successOrFailure: right(error)),
|
(error) => state.copyWith(successOrFailure: right(error)),
|
||||||
|
@ -1,43 +0,0 @@
|
|||||||
import 'package:dartz/dartz.dart';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
|
|
||||||
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
|
||||||
import 'package:freezed_annotation/freezed_annotation.dart';
|
|
||||||
import 'package:app_flowy/workspace/domain/i_view.dart';
|
|
||||||
|
|
||||||
part 'view_edit_bloc.freezed.dart';
|
|
||||||
|
|
||||||
class ViewEditBloc extends Bloc<ViewEditEvent, ViewEditState> {
|
|
||||||
final IView iViewImpl;
|
|
||||||
|
|
||||||
ViewEditBloc({
|
|
||||||
required this.iViewImpl,
|
|
||||||
}) : super(ViewEditState.initial());
|
|
||||||
|
|
||||||
@override
|
|
||||||
Stream<ViewEditState> mapEventToState(ViewEditEvent event) async* {
|
|
||||||
yield* event.map(initial: (_) async* {
|
|
||||||
yield state;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class ViewEditEvent with _$ViewEditEvent {
|
|
||||||
const factory ViewEditEvent.initial() = Initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
@freezed
|
|
||||||
class ViewEditState with _$ViewEditState {
|
|
||||||
const factory ViewEditState({
|
|
||||||
required bool isLoading,
|
|
||||||
required Option<View> view,
|
|
||||||
required Either<Unit, WorkspaceError> successOrFailure,
|
|
||||||
}) = _ViewState;
|
|
||||||
|
|
||||||
factory ViewEditState.initial() => ViewEditState(
|
|
||||||
isLoading: false,
|
|
||||||
view: none(),
|
|
||||||
successOrFailure: left(unit),
|
|
||||||
);
|
|
||||||
}
|
|
@ -1,332 +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 'view_edit_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 _$ViewEditEventTearOff {
|
|
||||||
const _$ViewEditEventTearOff();
|
|
||||||
|
|
||||||
Initial initial() {
|
|
||||||
return const Initial();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
const $ViewEditEvent = _$ViewEditEventTearOff();
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$ViewEditEvent {
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult when<TResult extends Object?>({
|
|
||||||
required TResult Function() initial,
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeWhen<TResult extends Object?>({
|
|
||||||
TResult Function()? initial,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult map<TResult extends Object?>({
|
|
||||||
required TResult Function(Initial value) initial,
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeMap<TResult extends Object?>({
|
|
||||||
TResult Function(Initial value)? initial,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $ViewEditEventCopyWith<$Res> {
|
|
||||||
factory $ViewEditEventCopyWith(
|
|
||||||
ViewEditEvent value, $Res Function(ViewEditEvent) then) =
|
|
||||||
_$ViewEditEventCopyWithImpl<$Res>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$ViewEditEventCopyWithImpl<$Res>
|
|
||||||
implements $ViewEditEventCopyWith<$Res> {
|
|
||||||
_$ViewEditEventCopyWithImpl(this._value, this._then);
|
|
||||||
|
|
||||||
final ViewEditEvent _value;
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Res Function(ViewEditEvent) _then;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $InitialCopyWith<$Res> {
|
|
||||||
factory $InitialCopyWith(Initial value, $Res Function(Initial) then) =
|
|
||||||
_$InitialCopyWithImpl<$Res>;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$InitialCopyWithImpl<$Res> extends _$ViewEditEventCopyWithImpl<$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 'ViewEditEvent.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,
|
|
||||||
}) {
|
|
||||||
return initial();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeWhen<TResult extends Object?>({
|
|
||||||
TResult Function()? initial,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (initial != null) {
|
|
||||||
return initial();
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult map<TResult extends Object?>({
|
|
||||||
required TResult Function(Initial value) initial,
|
|
||||||
}) {
|
|
||||||
return initial(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
@optionalTypeArgs
|
|
||||||
TResult maybeMap<TResult extends Object?>({
|
|
||||||
TResult Function(Initial value)? initial,
|
|
||||||
required TResult orElse(),
|
|
||||||
}) {
|
|
||||||
if (initial != null) {
|
|
||||||
return initial(this);
|
|
||||||
}
|
|
||||||
return orElse();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class Initial implements ViewEditEvent {
|
|
||||||
const factory Initial() = _$Initial;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$ViewEditStateTearOff {
|
|
||||||
const _$ViewEditStateTearOff();
|
|
||||||
|
|
||||||
_ViewState call(
|
|
||||||
{required bool isLoading,
|
|
||||||
required Option<View> view,
|
|
||||||
required Either<Unit, WorkspaceError> successOrFailure}) {
|
|
||||||
return _ViewState(
|
|
||||||
isLoading: isLoading,
|
|
||||||
view: view,
|
|
||||||
successOrFailure: successOrFailure,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
const $ViewEditState = _$ViewEditStateTearOff();
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
mixin _$ViewEditState {
|
|
||||||
bool get isLoading => throw _privateConstructorUsedError;
|
|
||||||
Option<View> get view => throw _privateConstructorUsedError;
|
|
||||||
Either<Unit, WorkspaceError> get successOrFailure =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
$ViewEditStateCopyWith<ViewEditState> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class $ViewEditStateCopyWith<$Res> {
|
|
||||||
factory $ViewEditStateCopyWith(
|
|
||||||
ViewEditState value, $Res Function(ViewEditState) then) =
|
|
||||||
_$ViewEditStateCopyWithImpl<$Res>;
|
|
||||||
$Res call(
|
|
||||||
{bool isLoading,
|
|
||||||
Option<View> view,
|
|
||||||
Either<Unit, WorkspaceError> successOrFailure});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class _$ViewEditStateCopyWithImpl<$Res>
|
|
||||||
implements $ViewEditStateCopyWith<$Res> {
|
|
||||||
_$ViewEditStateCopyWithImpl(this._value, this._then);
|
|
||||||
|
|
||||||
final ViewEditState _value;
|
|
||||||
// ignore: unused_field
|
|
||||||
final $Res Function(ViewEditState) _then;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? isLoading = freezed,
|
|
||||||
Object? view = freezed,
|
|
||||||
Object? successOrFailure = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_value.copyWith(
|
|
||||||
isLoading: isLoading == freezed
|
|
||||||
? _value.isLoading
|
|
||||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
view: view == freezed
|
|
||||||
? _value.view
|
|
||||||
: view // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Option<View>,
|
|
||||||
successOrFailure: successOrFailure == freezed
|
|
||||||
? _value.successOrFailure
|
|
||||||
: successOrFailure // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Either<Unit, WorkspaceError>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
abstract class _$ViewStateCopyWith<$Res>
|
|
||||||
implements $ViewEditStateCopyWith<$Res> {
|
|
||||||
factory _$ViewStateCopyWith(
|
|
||||||
_ViewState value, $Res Function(_ViewState) then) =
|
|
||||||
__$ViewStateCopyWithImpl<$Res>;
|
|
||||||
@override
|
|
||||||
$Res call(
|
|
||||||
{bool isLoading,
|
|
||||||
Option<View> view,
|
|
||||||
Either<Unit, WorkspaceError> successOrFailure});
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
class __$ViewStateCopyWithImpl<$Res> extends _$ViewEditStateCopyWithImpl<$Res>
|
|
||||||
implements _$ViewStateCopyWith<$Res> {
|
|
||||||
__$ViewStateCopyWithImpl(_ViewState _value, $Res Function(_ViewState) _then)
|
|
||||||
: super(_value, (v) => _then(v as _ViewState));
|
|
||||||
|
|
||||||
@override
|
|
||||||
_ViewState get _value => super._value as _ViewState;
|
|
||||||
|
|
||||||
@override
|
|
||||||
$Res call({
|
|
||||||
Object? isLoading = freezed,
|
|
||||||
Object? view = freezed,
|
|
||||||
Object? successOrFailure = freezed,
|
|
||||||
}) {
|
|
||||||
return _then(_ViewState(
|
|
||||||
isLoading: isLoading == freezed
|
|
||||||
? _value.isLoading
|
|
||||||
: isLoading // ignore: cast_nullable_to_non_nullable
|
|
||||||
as bool,
|
|
||||||
view: view == freezed
|
|
||||||
? _value.view
|
|
||||||
: view // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Option<View>,
|
|
||||||
successOrFailure: successOrFailure == freezed
|
|
||||||
? _value.successOrFailure
|
|
||||||
: successOrFailure // ignore: cast_nullable_to_non_nullable
|
|
||||||
as Either<Unit, WorkspaceError>,
|
|
||||||
));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @nodoc
|
|
||||||
|
|
||||||
class _$_ViewState implements _ViewState {
|
|
||||||
const _$_ViewState(
|
|
||||||
{required this.isLoading,
|
|
||||||
required this.view,
|
|
||||||
required this.successOrFailure});
|
|
||||||
|
|
||||||
@override
|
|
||||||
final bool isLoading;
|
|
||||||
@override
|
|
||||||
final Option<View> view;
|
|
||||||
@override
|
|
||||||
final Either<Unit, WorkspaceError> successOrFailure;
|
|
||||||
|
|
||||||
@override
|
|
||||||
String toString() {
|
|
||||||
return 'ViewEditState(isLoading: $isLoading, view: $view, successOrFailure: $successOrFailure)';
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool operator ==(dynamic other) {
|
|
||||||
return identical(this, other) ||
|
|
||||||
(other is _ViewState &&
|
|
||||||
(identical(other.isLoading, isLoading) ||
|
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.isLoading, isLoading)) &&
|
|
||||||
(identical(other.view, view) ||
|
|
||||||
const DeepCollectionEquality().equals(other.view, view)) &&
|
|
||||||
(identical(other.successOrFailure, successOrFailure) ||
|
|
||||||
const DeepCollectionEquality()
|
|
||||||
.equals(other.successOrFailure, successOrFailure)));
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
|
||||||
int get hashCode =>
|
|
||||||
runtimeType.hashCode ^
|
|
||||||
const DeepCollectionEquality().hash(isLoading) ^
|
|
||||||
const DeepCollectionEquality().hash(view) ^
|
|
||||||
const DeepCollectionEquality().hash(successOrFailure);
|
|
||||||
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
@override
|
|
||||||
_$ViewStateCopyWith<_ViewState> get copyWith =>
|
|
||||||
__$ViewStateCopyWithImpl<_ViewState>(this, _$identity);
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class _ViewState implements ViewEditState {
|
|
||||||
const factory _ViewState(
|
|
||||||
{required bool isLoading,
|
|
||||||
required Option<View> view,
|
|
||||||
required Either<Unit, WorkspaceError> successOrFailure}) = _$_ViewState;
|
|
||||||
|
|
||||||
@override
|
|
||||||
bool get isLoading => throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
Option<View> get view => throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
Either<Unit, WorkspaceError> get successOrFailure =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
@override
|
|
||||||
@JsonKey(ignore: true)
|
|
||||||
_$ViewStateCopyWith<_ViewState> get copyWith =>
|
|
||||||
throw _privateConstructorUsedError;
|
|
||||||
}
|
|
@ -7,7 +7,7 @@ typedef ViewUpdatedCallback = void Function(Either<View, WorkspaceError>);
|
|||||||
abstract class IView {
|
abstract class IView {
|
||||||
View get view;
|
View get view;
|
||||||
|
|
||||||
Future<Either<Unit, WorkspaceError>> pushIntoTrash();
|
Future<Either<Unit, WorkspaceError>> delete();
|
||||||
|
|
||||||
Future<Either<View, WorkspaceError>> rename(String newName);
|
Future<Either<View, WorkspaceError>> rename(String newName);
|
||||||
}
|
}
|
||||||
|
@ -13,8 +13,8 @@ class IViewImpl extends IView {
|
|||||||
View get view => repo.view;
|
View get view => repo.view;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<Either<Unit, WorkspaceError>> pushIntoTrash() {
|
Future<Either<Unit, WorkspaceError>> delete() {
|
||||||
return repo.updateView(isTrash: true).then((result) {
|
return repo.delete().then((result) {
|
||||||
return result.fold(
|
return result.fold(
|
||||||
(_) => left(unit),
|
(_) => left(unit),
|
||||||
(error) => right(error),
|
(error) => right(error),
|
||||||
|
@ -21,9 +21,7 @@ class AppRepository {
|
|||||||
});
|
});
|
||||||
|
|
||||||
Future<Either<App, WorkspaceError>> getAppDesc() {
|
Future<Either<App, WorkspaceError>> getAppDesc() {
|
||||||
final request = QueryAppRequest.create()
|
final request = QueryAppRequest.create()..appId = appId;
|
||||||
..appId = appId
|
|
||||||
..readBelongings = false;
|
|
||||||
|
|
||||||
return WorkspaceEventReadApp(request).send();
|
return WorkspaceEventReadApp(request).send();
|
||||||
}
|
}
|
||||||
@ -39,9 +37,7 @@ class AppRepository {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<List<View>, WorkspaceError>> getViews() {
|
Future<Either<List<View>, WorkspaceError>> getViews() {
|
||||||
final request = QueryAppRequest.create()
|
final request = QueryAppRequest.create()..appId = appId;
|
||||||
..appId = appId
|
|
||||||
..readBelongings = true;
|
|
||||||
|
|
||||||
return WorkspaceEventReadApp(request).send().then((result) {
|
return WorkspaceEventReadApp(request).send().then((result) {
|
||||||
return result.fold(
|
return result.fold(
|
||||||
|
@ -26,7 +26,7 @@ class ViewRepository {
|
|||||||
return WorkspaceEventReadView(request).send();
|
return WorkspaceEventReadView(request).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<View, WorkspaceError>> updateView({String? name, String? desc, bool? isTrash}) {
|
Future<Either<View, WorkspaceError>> updateView({String? name, String? desc}) {
|
||||||
final request = UpdateViewRequest.create()..viewId = view.id;
|
final request = UpdateViewRequest.create()..viewId = view.id;
|
||||||
|
|
||||||
if (name != null) {
|
if (name != null) {
|
||||||
@ -37,15 +37,11 @@ class ViewRepository {
|
|||||||
request.desc = desc;
|
request.desc = desc;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTrash != null) {
|
|
||||||
request.isTrash = isTrash;
|
|
||||||
}
|
|
||||||
|
|
||||||
return WorkspaceEventUpdateView(request).send();
|
return WorkspaceEventUpdateView(request).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<Either<Unit, WorkspaceError>> delete() {
|
Future<Either<Unit, WorkspaceError>> delete() {
|
||||||
final request = DeleteViewRequest.create()..viewId = view.id;
|
final request = DeleteViewRequest.create()..viewIds.add(view.id);
|
||||||
return WorkspaceEventDeleteView(request).send();
|
return WorkspaceEventDeleteView(request).send();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -149,7 +149,9 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
|||||||
height: 42,
|
height: 42,
|
||||||
child: TrashCell(
|
child: TrashCell(
|
||||||
object: object,
|
object: object,
|
||||||
onRestore: () => context.read<TrashBloc>().add(TrashEvent.putback(object.id)),
|
onRestore: () {
|
||||||
|
context.read<TrashBloc>().add(TrashEvent.putback(object.id));
|
||||||
|
},
|
||||||
onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
|
onDelete: () => context.read<TrashBloc>().add(TrashEvent.delete(object.id)),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,16 +1,15 @@
|
|||||||
use crate::{
|
use crate::{
|
||||||
entities::{
|
entities::trash::{RepeatedTrash, TrashIdentifier},
|
||||||
trash::{RepeatedTrash, TrashIdentifier},
|
|
||||||
},
|
|
||||||
errors::WorkspaceError,
|
errors::WorkspaceError,
|
||||||
services::TrashCan,
|
services::TrashCan,
|
||||||
};
|
};
|
||||||
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
|
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
|
||||||
use std::{sync::Arc};
|
use std::sync::Arc;
|
||||||
|
|
||||||
#[tracing::instrument(skip(controller), err)]
|
#[tracing::instrument(skip(controller), err)]
|
||||||
pub(crate) async fn read_trash_handler(controller: Unit<Arc<TrashCan>>) -> DataResult<RepeatedTrash, WorkspaceError> {
|
pub(crate) async fn read_trash_handler(controller: Unit<Arc<TrashCan>>) -> DataResult<RepeatedTrash, WorkspaceError> {
|
||||||
let repeated_trash = controller.read_trash()?;
|
let conn = controller.database.db_connection()?;
|
||||||
|
let repeated_trash = controller.read_trash(&conn)?;
|
||||||
data_result(repeated_trash)
|
data_result(repeated_trash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -41,7 +41,7 @@ impl TrashEvent {
|
|||||||
}
|
}
|
||||||
|
|
||||||
pub struct TrashCan {
|
pub struct TrashCan {
|
||||||
database: Arc<dyn WorkspaceDatabase>,
|
pub database: Arc<dyn WorkspaceDatabase>,
|
||||||
notify: broadcast::Sender<TrashEvent>,
|
notify: broadcast::Sender<TrashEvent>,
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -51,16 +51,36 @@ impl TrashCan {
|
|||||||
|
|
||||||
Self { database, notify: tx }
|
Self { database, notify: tx }
|
||||||
}
|
}
|
||||||
pub fn read_trash(&self) -> Result<RepeatedTrash, WorkspaceError> {
|
|
||||||
let conn = self.database.db_connection()?;
|
pub fn read_trash(&self, conn: &SqliteConnection) -> Result<RepeatedTrash, WorkspaceError> {
|
||||||
let repeated_trash = TrashTableSql::read_all(&*conn)?;
|
let repeated_trash = TrashTableSql::read_all(&*conn)?;
|
||||||
Ok(repeated_trash)
|
Ok(repeated_trash)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn trash_ids(&self, conn: &SqliteConnection) -> Result<Vec<String>, WorkspaceError> {
|
||||||
|
let ids = TrashTableSql::read_all(&*conn)?
|
||||||
|
.take_items()
|
||||||
|
.into_iter()
|
||||||
|
.map(|item| item.id)
|
||||||
|
.collect::<Vec<String>>();
|
||||||
|
Ok(ids)
|
||||||
|
}
|
||||||
|
|
||||||
#[tracing::instrument(level = "debug", skip(self), fields(putback) err)]
|
#[tracing::instrument(level = "debug", skip(self), fields(putback) err)]
|
||||||
pub async fn putback(&self, trash_id: &str) -> WorkspaceResult<()> {
|
pub async fn putback(&self, trash_id: &str) -> WorkspaceResult<()> {
|
||||||
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
||||||
let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
|
let trash_table = TrashTableSql::read(trash_id, &*self.database.db_connection()?)?;
|
||||||
|
let _ = thread::scope(|_s| {
|
||||||
|
let conn = self.database.db_connection()?;
|
||||||
|
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
|
let _ = TrashTableSql::delete_trash(trash_id, &*conn)?;
|
||||||
|
let _ = self.notify_dart_trash_did_update(&conn)?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
Ok::<(), WorkspaceError>(())
|
||||||
|
})
|
||||||
|
.unwrap()?;
|
||||||
|
|
||||||
tracing::Span::current().record(
|
tracing::Span::current().record(
|
||||||
"putback",
|
"putback",
|
||||||
&format!("{:?}: {}", &trash_table.ty, trash_table.id).as_str(),
|
&format!("{:?}: {}", &trash_table.ty, trash_table.id).as_str(),
|
||||||
@ -70,12 +90,6 @@ impl TrashCan {
|
|||||||
.send(TrashEvent::Putback(trash_table.ty.into(), vec![trash_table.id], tx));
|
.send(TrashEvent::Putback(trash_table.ty.into(), vec![trash_table.id], tx));
|
||||||
|
|
||||||
let _ = rx.recv().await.unwrap()?;
|
let _ = rx.recv().await.unwrap()?;
|
||||||
let conn = self.database.db_connection()?;
|
|
||||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
|
||||||
let _ = TrashTableSql::delete_trash(trash_id, &*conn)?;
|
|
||||||
let _ = self.notify_dart_trash_did_update(&conn)?;
|
|
||||||
Ok(())
|
|
||||||
})?;
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -122,10 +136,12 @@ impl TrashCan {
|
|||||||
if trash_type.as_ref().unwrap() != &t.ty {
|
if trash_type.as_ref().unwrap() != &t.ty {
|
||||||
return Err(WorkspaceError::internal());
|
return Err(WorkspaceError::internal());
|
||||||
}
|
}
|
||||||
|
let trash_id = t.id.clone();
|
||||||
ids.push(t.id.clone());
|
log::debug!("create trash: {:?}", t);
|
||||||
let _ = TrashTableSql::create_trash(t.into(), &*conn)?;
|
let _ = TrashTableSql::create_trash(t.into(), &*conn)?;
|
||||||
|
ids.push(trash_id);
|
||||||
}
|
}
|
||||||
|
let _ = self.notify_dart_trash_did_update(&conn)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok::<(), WorkspaceError>(())
|
Ok::<(), WorkspaceError>(())
|
||||||
|
@ -59,12 +59,12 @@ impl ViewController {
|
|||||||
pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
|
pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
|
||||||
let view = self.create_view_on_server(params.clone()).await?;
|
let view = self.create_view_on_server(params.clone()).await?;
|
||||||
let conn = &*self.database.db_connection()?;
|
let conn = &*self.database.db_connection()?;
|
||||||
|
let trash_can = self.trash_can.clone();
|
||||||
// TODO: rollback anything created before if failed?
|
// TODO: rollback anything created before if failed?
|
||||||
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
let _ = self.save_view(view.clone(), conn)?;
|
let _ = self.save_view(view.clone(), conn)?;
|
||||||
self.document.create(CreateDocParams::new(&view.id, params.data))?;
|
self.document.create(CreateDocParams::new(&view.id, params.data))?;
|
||||||
|
let repeated_view = read_belonging_view(&view.belong_to_id, trash_can, &conn)?;
|
||||||
let repeated_view = ViewTableSql::read_views(&view.belong_to_id, conn)?;
|
|
||||||
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
||||||
.payload(repeated_view)
|
.payload(repeated_view)
|
||||||
.send();
|
.send();
|
||||||
@ -112,7 +112,7 @@ impl ViewController {
|
|||||||
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
|
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
|
||||||
// TODO: read from server
|
// TODO: read from server
|
||||||
let conn = self.database.db_connection()?;
|
let conn = self.database.db_connection()?;
|
||||||
let repeated_view = ViewTableSql::read_views(belong_to_id, &*conn)?;
|
let repeated_view = read_belonging_view(belong_to_id, self.trash_can.clone(), &conn)?;
|
||||||
Ok(repeated_view)
|
Ok(repeated_view)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -165,22 +165,22 @@ impl ViewController {
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[tracing::instrument(skip(self), err)]
|
// #[tracing::instrument(skip(self), err)]
|
||||||
fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(), WorkspaceError> {
|
// fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(),
|
||||||
let token = self.user.token()?;
|
// WorkspaceError> { let token = self.user.token()?;
|
||||||
let server = self.server.clone();
|
// let server = self.server.clone();
|
||||||
let params = DeleteViewParams { view_ids };
|
// let params = DeleteViewParams { view_ids };
|
||||||
spawn(async move {
|
// spawn(async move {
|
||||||
match server.delete_view(&token, params).await {
|
// match server.delete_view(&token, params).await {
|
||||||
Ok(_) => {},
|
// Ok(_) => {},
|
||||||
Err(e) => {
|
// Err(e) => {
|
||||||
// TODO: retry?
|
// // TODO: retry?
|
||||||
log::error!("Delete view failed: {:?}", e);
|
// log::error!("Delete view failed: {:?}", e);
|
||||||
},
|
// },
|
||||||
}
|
// }
|
||||||
});
|
// });
|
||||||
Ok(())
|
// Ok(())
|
||||||
}
|
// }
|
||||||
|
|
||||||
#[tracing::instrument(skip(self), err)]
|
#[tracing::instrument(skip(self), err)]
|
||||||
fn read_view_on_server(&self, params: ViewIdentifier) -> Result<(), WorkspaceError> {
|
fn read_view_on_server(&self, params: ViewIdentifier) -> Result<(), WorkspaceError> {
|
||||||
@ -202,6 +202,7 @@ impl ViewController {
|
|||||||
let mut rx = self.trash_can.subscribe();
|
let mut rx = self.trash_can.subscribe();
|
||||||
let database = self.database.clone();
|
let database = self.database.clone();
|
||||||
let document = self.document.clone();
|
let document = self.document.clone();
|
||||||
|
let trash_can = self.trash_can.clone();
|
||||||
let _ = tokio::spawn(async move {
|
let _ = tokio::spawn(async move {
|
||||||
loop {
|
loop {
|
||||||
let mut stream = Box::pin(rx.recv().into_stream().filter_map(|result| async move {
|
let mut stream = Box::pin(rx.recv().into_stream().filter_map(|result| async move {
|
||||||
@ -212,7 +213,9 @@ impl ViewController {
|
|||||||
}));
|
}));
|
||||||
let event: Option<TrashEvent> = stream.next().await;
|
let event: Option<TrashEvent> = stream.next().await;
|
||||||
match event {
|
match event {
|
||||||
Some(event) => handle_trash_event(database.clone(), document.clone(), event),
|
Some(event) => {
|
||||||
|
handle_trash_event(database.clone(), document.clone(), trash_can.clone(), event).await
|
||||||
|
},
|
||||||
None => {},
|
None => {},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -220,7 +223,12 @@ impl ViewController {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyDocument>, event: TrashEvent) {
|
async fn handle_trash_event(
|
||||||
|
database: Arc<dyn WorkspaceDatabase>,
|
||||||
|
document: Arc<FlowyDocument>,
|
||||||
|
trash_can: Arc<TrashCan>,
|
||||||
|
event: TrashEvent,
|
||||||
|
) {
|
||||||
let db_result = database.db_connection();
|
let db_result = database.db_connection();
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
@ -229,13 +237,13 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyD
|
|||||||
let conn = &*db_result?;
|
let conn = &*db_result?;
|
||||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||||
for view_id in view_ids {
|
for view_id in view_ids {
|
||||||
let _ = notify_view_num_did_change(&view_id, conn)?;
|
let _ = notify_view_num_did_change(&view_id, conn, trash_can.clone())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok::<(), WorkspaceError>(())
|
Ok::<(), WorkspaceError>(())
|
||||||
};
|
};
|
||||||
let _ = ret.send(result());
|
let _ = ret.send(result()).await;
|
||||||
},
|
},
|
||||||
TrashEvent::Delete(_, delete_ids, ret) => {
|
TrashEvent::Delete(_, delete_ids, ret) => {
|
||||||
let result = || {
|
let result = || {
|
||||||
@ -244,22 +252,34 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyD
|
|||||||
for view_id in delete_ids {
|
for view_id in delete_ids {
|
||||||
let _ = ViewTableSql::delete_view(&view_id, conn)?;
|
let _ = ViewTableSql::delete_view(&view_id, conn)?;
|
||||||
let _ = document.delete(view_id.clone().into())?;
|
let _ = document.delete(view_id.clone().into())?;
|
||||||
let _ = notify_view_num_did_change(&view_id, conn)?;
|
let _ = notify_view_num_did_change(&view_id, conn, trash_can.clone())?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
})?;
|
})?;
|
||||||
Ok::<(), WorkspaceError>(())
|
Ok::<(), WorkspaceError>(())
|
||||||
};
|
};
|
||||||
let _ = ret.send(result());
|
let _ = ret.send(result()).await;
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn notify_view_num_did_change(view_id: &str, conn: &SqliteConnection) -> WorkspaceResult<()> {
|
#[tracing::instrument(skip(conn, trash_can), err)]
|
||||||
|
fn notify_view_num_did_change(view_id: &str, conn: &SqliteConnection, trash_can: Arc<TrashCan>) -> WorkspaceResult<()> {
|
||||||
let view_table = ViewTableSql::read_view(view_id, conn)?;
|
let view_table = ViewTableSql::read_view(view_id, conn)?;
|
||||||
let repeated_view = ViewTableSql::read_views(&view_table.belong_to_id, conn)?;
|
let repeated_view = read_belonging_view(&view_table.belong_to_id, trash_can, conn)?;
|
||||||
send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
send_dart_notification(&view_table.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
||||||
.payload(repeated_view)
|
.payload(repeated_view)
|
||||||
.send();
|
.send();
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn read_belonging_view(
|
||||||
|
belong_to_id: &str,
|
||||||
|
trash_can: Arc<TrashCan>,
|
||||||
|
conn: &SqliteConnection,
|
||||||
|
) -> WorkspaceResult<RepeatedView> {
|
||||||
|
let mut repeated_view = ViewTableSql::read_views(belong_to_id, conn)?;
|
||||||
|
let trash_ids = trash_can.trash_ids(conn)?;
|
||||||
|
repeated_view.retain(|view| !trash_ids.contains(&view.id));
|
||||||
|
Ok(repeated_view)
|
||||||
|
}
|
||||||
|
@ -35,29 +35,16 @@ impl ViewTableSql {
|
|||||||
.filter(view_table::id.eq(view_id))
|
.filter(view_table::id.eq(view_id))
|
||||||
.first::<ViewTable>(conn)?;
|
.first::<ViewTable>(conn)?;
|
||||||
|
|
||||||
let repeated_trash: Vec<String> = trash_table::dsl::trash_table.select(trash_table::dsl::id).load(conn)?;
|
|
||||||
|
|
||||||
if repeated_trash.contains(&view_table.id) {
|
|
||||||
return Err(WorkspaceError::not_found());
|
|
||||||
}
|
|
||||||
|
|
||||||
Ok(view_table)
|
Ok(view_table)
|
||||||
}
|
}
|
||||||
|
|
||||||
// belong_to_id will be the app_id or view_id.
|
// belong_to_id will be the app_id or view_id.
|
||||||
pub(crate) fn read_views(belong_to_id: &str, conn: &SqliteConnection) -> Result<RepeatedView, WorkspaceError> {
|
pub(crate) fn read_views(belong_to_id: &str, conn: &SqliteConnection) -> Result<RepeatedView, WorkspaceError> {
|
||||||
let mut view_tables = dsl::view_table
|
let view_tables = dsl::view_table
|
||||||
.filter(view_table::belong_to_id.eq(belong_to_id))
|
.filter(view_table::belong_to_id.eq(belong_to_id))
|
||||||
.into_boxed()
|
.into_boxed()
|
||||||
.load::<ViewTable>(conn)?;
|
.load::<ViewTable>(conn)?;
|
||||||
|
|
||||||
let repeated_trash: Vec<String> = trash_table::dsl::trash_table.select(trash_table::dsl::id).load(conn)?;
|
|
||||||
|
|
||||||
view_tables = view_tables
|
|
||||||
.into_iter()
|
|
||||||
.filter(|table| !repeated_trash.contains(&table.id))
|
|
||||||
.collect::<Vec<ViewTable>>();
|
|
||||||
|
|
||||||
let views = view_tables
|
let views = view_tables
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.map(|view_table| view_table.into())
|
.map(|view_table| view_table.into())
|
||||||
|
Loading…
Reference in New Issue
Block a user