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
|
||||
// ignore: unnecessary_overrides
|
||||
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);
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,10 @@ class TrashBloc extends Bloc<TrashEvent, TrashState> {
|
||||
},
|
||||
putback: (e) async* {
|
||||
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* {
|
||||
final result = await iTrash.delete(e.trashId);
|
||||
|
@ -32,7 +32,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
|
||||
(error) => state.copyWith(successOrFailure: right(error)),
|
||||
);
|
||||
}, delete: (e) async* {
|
||||
final result = await iViewImpl.pushIntoTrash();
|
||||
final result = await iViewImpl.delete();
|
||||
yield result.fold(
|
||||
(l) => state.copyWith(successOrFailure: left(unit)),
|
||||
(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 {
|
||||
View get view;
|
||||
|
||||
Future<Either<Unit, WorkspaceError>> pushIntoTrash();
|
||||
Future<Either<Unit, WorkspaceError>> delete();
|
||||
|
||||
Future<Either<View, WorkspaceError>> rename(String newName);
|
||||
}
|
||||
|
@ -13,8 +13,8 @@ class IViewImpl extends IView {
|
||||
View get view => repo.view;
|
||||
|
||||
@override
|
||||
Future<Either<Unit, WorkspaceError>> pushIntoTrash() {
|
||||
return repo.updateView(isTrash: true).then((result) {
|
||||
Future<Either<Unit, WorkspaceError>> delete() {
|
||||
return repo.delete().then((result) {
|
||||
return result.fold(
|
||||
(_) => left(unit),
|
||||
(error) => right(error),
|
||||
|
@ -21,9 +21,7 @@ class AppRepository {
|
||||
});
|
||||
|
||||
Future<Either<App, WorkspaceError>> getAppDesc() {
|
||||
final request = QueryAppRequest.create()
|
||||
..appId = appId
|
||||
..readBelongings = false;
|
||||
final request = QueryAppRequest.create()..appId = appId;
|
||||
|
||||
return WorkspaceEventReadApp(request).send();
|
||||
}
|
||||
@ -39,9 +37,7 @@ class AppRepository {
|
||||
}
|
||||
|
||||
Future<Either<List<View>, WorkspaceError>> getViews() {
|
||||
final request = QueryAppRequest.create()
|
||||
..appId = appId
|
||||
..readBelongings = true;
|
||||
final request = QueryAppRequest.create()..appId = appId;
|
||||
|
||||
return WorkspaceEventReadApp(request).send().then((result) {
|
||||
return result.fold(
|
||||
|
@ -26,7 +26,7 @@ class ViewRepository {
|
||||
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;
|
||||
|
||||
if (name != null) {
|
||||
@ -37,15 +37,11 @@ class ViewRepository {
|
||||
request.desc = desc;
|
||||
}
|
||||
|
||||
if (isTrash != null) {
|
||||
request.isTrash = isTrash;
|
||||
}
|
||||
|
||||
return WorkspaceEventUpdateView(request).send();
|
||||
}
|
||||
|
||||
Future<Either<Unit, WorkspaceError>> delete() {
|
||||
final request = DeleteViewRequest.create()..viewId = view.id;
|
||||
final request = DeleteViewRequest.create()..viewIds.add(view.id);
|
||||
return WorkspaceEventDeleteView(request).send();
|
||||
}
|
||||
}
|
||||
|
@ -149,7 +149,9 @@ class _TrashStackPageState extends State<TrashStackPage> {
|
||||
height: 42,
|
||||
child: TrashCell(
|
||||
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)),
|
||||
),
|
||||
);
|
||||
|
@ -1,16 +1,15 @@
|
||||
use crate::{
|
||||
entities::{
|
||||
trash::{RepeatedTrash, TrashIdentifier},
|
||||
},
|
||||
entities::trash::{RepeatedTrash, TrashIdentifier},
|
||||
errors::WorkspaceError,
|
||||
services::TrashCan,
|
||||
};
|
||||
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
|
||||
use std::{sync::Arc};
|
||||
use std::sync::Arc;
|
||||
|
||||
#[tracing::instrument(skip(controller), err)]
|
||||
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)
|
||||
}
|
||||
|
||||
|
@ -41,7 +41,7 @@ impl TrashEvent {
|
||||
}
|
||||
|
||||
pub struct TrashCan {
|
||||
database: Arc<dyn WorkspaceDatabase>,
|
||||
pub database: Arc<dyn WorkspaceDatabase>,
|
||||
notify: broadcast::Sender<TrashEvent>,
|
||||
}
|
||||
|
||||
@ -51,16 +51,36 @@ impl TrashCan {
|
||||
|
||||
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)?;
|
||||
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)]
|
||||
pub async fn putback(&self, trash_id: &str) -> WorkspaceResult<()> {
|
||||
let (tx, mut rx) = mpsc::channel::<WorkspaceResult<()>>(1);
|
||||
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(
|
||||
"putback",
|
||||
&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));
|
||||
|
||||
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(())
|
||||
}
|
||||
|
||||
@ -122,10 +136,12 @@ impl TrashCan {
|
||||
if trash_type.as_ref().unwrap() != &t.ty {
|
||||
return Err(WorkspaceError::internal());
|
||||
}
|
||||
|
||||
ids.push(t.id.clone());
|
||||
let trash_id = t.id.clone();
|
||||
log::debug!("create trash: {:?}", t);
|
||||
let _ = TrashTableSql::create_trash(t.into(), &*conn)?;
|
||||
ids.push(trash_id);
|
||||
}
|
||||
let _ = self.notify_dart_trash_did_update(&conn)?;
|
||||
Ok(())
|
||||
})?;
|
||||
Ok::<(), WorkspaceError>(())
|
||||
|
@ -59,12 +59,12 @@ impl ViewController {
|
||||
pub(crate) async fn create_view(&self, params: CreateViewParams) -> Result<View, WorkspaceError> {
|
||||
let view = self.create_view_on_server(params.clone()).await?;
|
||||
let conn = &*self.database.db_connection()?;
|
||||
let trash_can = self.trash_can.clone();
|
||||
// TODO: rollback anything created before if failed?
|
||||
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||
let _ = self.save_view(view.clone(), conn)?;
|
||||
self.document.create(CreateDocParams::new(&view.id, params.data))?;
|
||||
|
||||
let repeated_view = ViewTableSql::read_views(&view.belong_to_id, conn)?;
|
||||
let repeated_view = read_belonging_view(&view.belong_to_id, trash_can, &conn)?;
|
||||
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
|
||||
.payload(repeated_view)
|
||||
.send();
|
||||
@ -112,7 +112,7 @@ impl ViewController {
|
||||
pub(crate) async fn read_views_belong_to(&self, belong_to_id: &str) -> Result<RepeatedView, WorkspaceError> {
|
||||
// TODO: read from server
|
||||
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)
|
||||
}
|
||||
|
||||
@ -165,22 +165,22 @@ impl ViewController {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tracing::instrument(skip(self), err)]
|
||||
fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(), WorkspaceError> {
|
||||
let token = self.user.token()?;
|
||||
let server = self.server.clone();
|
||||
let params = DeleteViewParams { view_ids };
|
||||
spawn(async move {
|
||||
match server.delete_view(&token, params).await {
|
||||
Ok(_) => {},
|
||||
Err(e) => {
|
||||
// TODO: retry?
|
||||
log::error!("Delete view failed: {:?}", e);
|
||||
},
|
||||
}
|
||||
});
|
||||
Ok(())
|
||||
}
|
||||
// #[tracing::instrument(skip(self), err)]
|
||||
// fn delete_view_on_server(&self, view_ids: Vec<String>) -> Result<(),
|
||||
// WorkspaceError> { let token = self.user.token()?;
|
||||
// let server = self.server.clone();
|
||||
// let params = DeleteViewParams { view_ids };
|
||||
// spawn(async move {
|
||||
// match server.delete_view(&token, params).await {
|
||||
// Ok(_) => {},
|
||||
// Err(e) => {
|
||||
// // TODO: retry?
|
||||
// log::error!("Delete view failed: {:?}", e);
|
||||
// },
|
||||
// }
|
||||
// });
|
||||
// Ok(())
|
||||
// }
|
||||
|
||||
#[tracing::instrument(skip(self), err)]
|
||||
fn read_view_on_server(&self, params: ViewIdentifier) -> Result<(), WorkspaceError> {
|
||||
@ -202,6 +202,7 @@ impl ViewController {
|
||||
let mut rx = self.trash_can.subscribe();
|
||||
let database = self.database.clone();
|
||||
let document = self.document.clone();
|
||||
let trash_can = self.trash_can.clone();
|
||||
let _ = tokio::spawn(async move {
|
||||
loop {
|
||||
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;
|
||||
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 => {},
|
||||
}
|
||||
}
|
||||
@ -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();
|
||||
|
||||
match event {
|
||||
@ -229,13 +237,13 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyD
|
||||
let conn = &*db_result?;
|
||||
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
|
||||
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::<(), WorkspaceError>(())
|
||||
};
|
||||
let _ = ret.send(result());
|
||||
let _ = ret.send(result()).await;
|
||||
},
|
||||
TrashEvent::Delete(_, delete_ids, ret) => {
|
||||
let result = || {
|
||||
@ -244,22 +252,34 @@ fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, document: Arc<FlowyD
|
||||
for view_id in delete_ids {
|
||||
let _ = ViewTableSql::delete_view(&view_id, conn)?;
|
||||
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::<(), 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 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)
|
||||
.payload(repeated_view)
|
||||
.send();
|
||||
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))
|
||||
.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)
|
||||
}
|
||||
|
||||
// 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> {
|
||||
let mut view_tables = dsl::view_table
|
||||
let view_tables = dsl::view_table
|
||||
.filter(view_table::belong_to_id.eq(belong_to_id))
|
||||
.into_boxed()
|
||||
.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
|
||||
.into_iter()
|
||||
.map(|view_table| view_table.into())
|
||||
|
Loading…
Reference in New Issue
Block a user