[rust]: delete app

This commit is contained in:
appflowy 2021-10-30 17:19:50 +08:00
parent dd9456e7ff
commit 4966b03123
55 changed files with 867 additions and 448 deletions

View File

@ -1,5 +1,6 @@
import 'package:app_flowy/workspace/domain/i_app.dart'; import 'package:app_flowy/workspace/domain/i_app.dart';
import 'package:flowy_log/flowy_log.dart'; import 'package:flowy_log/flowy_log.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:freezed_annotation/freezed_annotation.dart'; import 'package:freezed_annotation/freezed_annotation.dart';
@ -11,7 +12,7 @@ part 'app_bloc.freezed.dart';
class AppBloc extends Bloc<AppEvent, AppState> { class AppBloc extends Bloc<AppEvent, AppState> {
final IApp appManager; final IApp appManager;
final IAppListenr listener; final IAppListenr listener;
AppBloc({required this.appManager, required this.listener}) : super(AppState.initial()); AppBloc({required App app, required this.appManager, required this.listener}) : super(AppState.initial(app));
@override @override
Stream<AppState> mapEventToState( Stream<AppState> mapEventToState(
@ -20,7 +21,6 @@ class AppBloc extends Bloc<AppEvent, AppState> {
yield* event.map( yield* event.map(
initial: (e) async* { initial: (e) async* {
listener.start(viewsChangeCallback: _handleViewsOrFail); listener.start(viewsChangeCallback: _handleViewsOrFail);
yield* _fetchViews(); yield* _fetchViews();
}, },
createView: (CreateView value) async* { createView: (CreateView value) async* {
@ -39,6 +39,20 @@ class AppBloc extends Bloc<AppEvent, AppState> {
didReceiveViews: (e) async* { didReceiveViews: (e) async* {
yield state.copyWith(views: e.views); yield state.copyWith(views: e.views);
}, },
delete: (e) async* {
final result = await appManager.delete();
yield result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
);
},
rename: (e) async* {
final result = await appManager.rename(e.newName);
yield result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
);
},
); );
} }
@ -73,19 +87,23 @@ class AppBloc extends Bloc<AppEvent, AppState> {
class AppEvent with _$AppEvent { class AppEvent with _$AppEvent {
const factory AppEvent.initial() = Initial; const factory AppEvent.initial() = Initial;
const factory AppEvent.createView(String name, String desc, ViewType viewType) = CreateView; const factory AppEvent.createView(String name, String desc, ViewType viewType) = CreateView;
const factory AppEvent.delete() = Delete;
const factory AppEvent.rename(String newName) = Rename;
const factory AppEvent.didReceiveViews(List<View> views) = ReceiveViews; const factory AppEvent.didReceiveViews(List<View> views) = ReceiveViews;
} }
@freezed @freezed
class AppState with _$AppState { class AppState with _$AppState {
const factory AppState({ const factory AppState({
required App app,
required bool isLoading, required bool isLoading,
required List<View>? views, required List<View>? views,
View? selectedView, View? selectedView,
required Either<Unit, WorkspaceError> successOrFailure, required Either<Unit, WorkspaceError> successOrFailure,
}) = _AppState; }) = _AppState;
factory AppState.initial() => AppState( factory AppState.initial(App app) => AppState(
app: app,
isLoading: false, isLoading: false,
views: null, views: null,
selectedView: null, selectedView: null,

View File

@ -28,6 +28,16 @@ class _$AppEventTearOff {
); );
} }
Delete delete() {
return const Delete();
}
Rename rename(String newName) {
return Rename(
newName,
);
}
ReceiveViews didReceiveViews(List<View> views) { ReceiveViews didReceiveViews(List<View> views) {
return ReceiveViews( return ReceiveViews(
views, views,
@ -45,6 +55,8 @@ mixin _$AppEvent {
required TResult Function() initial, required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType) required TResult Function(String name, String desc, ViewType viewType)
createView, createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews, required TResult Function(List<View> views) didReceiveViews,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@ -52,6 +64,8 @@ mixin _$AppEvent {
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView, TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews, TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) => }) =>
@ -60,6 +74,8 @@ mixin _$AppEvent {
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView, required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews, required TResult Function(ReceiveViews value) didReceiveViews,
}) => }) =>
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
@ -67,6 +83,8 @@ mixin _$AppEvent {
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView, TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews, TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) => }) =>
@ -128,6 +146,8 @@ class _$Initial implements Initial {
required TResult Function() initial, required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType) required TResult Function(String name, String desc, ViewType viewType)
createView, createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews, required TResult Function(List<View> views) didReceiveViews,
}) { }) {
return initial(); return initial();
@ -138,6 +158,8 @@ class _$Initial implements Initial {
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView, TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews, TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -152,6 +174,8 @@ class _$Initial implements Initial {
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView, required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews, required TResult Function(ReceiveViews value) didReceiveViews,
}) { }) {
return initial(this); return initial(this);
@ -162,6 +186,8 @@ class _$Initial implements Initial {
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView, TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews, TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -264,6 +290,8 @@ class _$CreateView implements CreateView {
required TResult Function() initial, required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType) required TResult Function(String name, String desc, ViewType viewType)
createView, createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews, required TResult Function(List<View> views) didReceiveViews,
}) { }) {
return createView(name, desc, viewType); return createView(name, desc, viewType);
@ -274,6 +302,8 @@ class _$CreateView implements CreateView {
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView, TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews, TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -288,6 +318,8 @@ class _$CreateView implements CreateView {
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView, required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews, required TResult Function(ReceiveViews value) didReceiveViews,
}) { }) {
return createView(this); return createView(this);
@ -298,6 +330,8 @@ class _$CreateView implements CreateView {
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView, TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews, TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -320,6 +354,227 @@ abstract class CreateView implements AppEvent {
throw _privateConstructorUsedError; throw _privateConstructorUsedError;
} }
/// @nodoc
abstract class $DeleteCopyWith<$Res> {
factory $DeleteCopyWith(Delete value, $Res Function(Delete) then) =
_$DeleteCopyWithImpl<$Res>;
}
/// @nodoc
class _$DeleteCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
implements $DeleteCopyWith<$Res> {
_$DeleteCopyWithImpl(Delete _value, $Res Function(Delete) _then)
: super(_value, (v) => _then(v as Delete));
@override
Delete get _value => super._value as Delete;
}
/// @nodoc
class _$Delete implements Delete {
const _$Delete();
@override
String toString() {
return 'AppEvent.delete()';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) || (other is Delete);
}
@override
int get hashCode => runtimeType.hashCode;
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType)
createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews,
}) {
return delete();
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(),
}) {
if (delete != null) {
return delete();
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews,
}) {
return delete(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(),
}) {
if (delete != null) {
return delete(this);
}
return orElse();
}
}
abstract class Delete implements AppEvent {
const factory Delete() = _$Delete;
}
/// @nodoc
abstract class $RenameCopyWith<$Res> {
factory $RenameCopyWith(Rename value, $Res Function(Rename) then) =
_$RenameCopyWithImpl<$Res>;
$Res call({String newName});
}
/// @nodoc
class _$RenameCopyWithImpl<$Res> extends _$AppEventCopyWithImpl<$Res>
implements $RenameCopyWith<$Res> {
_$RenameCopyWithImpl(Rename _value, $Res Function(Rename) _then)
: super(_value, (v) => _then(v as Rename));
@override
Rename get _value => super._value as Rename;
@override
$Res call({
Object? newName = freezed,
}) {
return _then(Rename(
newName == freezed
? _value.newName
: newName // ignore: cast_nullable_to_non_nullable
as String,
));
}
}
/// @nodoc
class _$Rename implements Rename {
const _$Rename(this.newName);
@override
final String newName;
@override
String toString() {
return 'AppEvent.rename(newName: $newName)';
}
@override
bool operator ==(dynamic other) {
return identical(this, other) ||
(other is Rename &&
(identical(other.newName, newName) ||
const DeepCollectionEquality().equals(other.newName, newName)));
}
@override
int get hashCode =>
runtimeType.hashCode ^ const DeepCollectionEquality().hash(newName);
@JsonKey(ignore: true)
@override
$RenameCopyWith<Rename> get copyWith =>
_$RenameCopyWithImpl<Rename>(this, _$identity);
@override
@optionalTypeArgs
TResult when<TResult extends Object?>({
required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType)
createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews,
}) {
return rename(newName);
}
@override
@optionalTypeArgs
TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(),
}) {
if (rename != null) {
return rename(newName);
}
return orElse();
}
@override
@optionalTypeArgs
TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews,
}) {
return rename(this);
}
@override
@optionalTypeArgs
TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(),
}) {
if (rename != null) {
return rename(this);
}
return orElse();
}
}
abstract class Rename implements AppEvent {
const factory Rename(String newName) = _$Rename;
String get newName => throw _privateConstructorUsedError;
@JsonKey(ignore: true)
$RenameCopyWith<Rename> get copyWith => throw _privateConstructorUsedError;
}
/// @nodoc /// @nodoc
abstract class $ReceiveViewsCopyWith<$Res> { abstract class $ReceiveViewsCopyWith<$Res> {
factory $ReceiveViewsCopyWith( factory $ReceiveViewsCopyWith(
@ -387,6 +642,8 @@ class _$ReceiveViews implements ReceiveViews {
required TResult Function() initial, required TResult Function() initial,
required TResult Function(String name, String desc, ViewType viewType) required TResult Function(String name, String desc, ViewType viewType)
createView, createView,
required TResult Function() delete,
required TResult Function(String newName) rename,
required TResult Function(List<View> views) didReceiveViews, required TResult Function(List<View> views) didReceiveViews,
}) { }) {
return didReceiveViews(views); return didReceiveViews(views);
@ -397,6 +654,8 @@ class _$ReceiveViews implements ReceiveViews {
TResult maybeWhen<TResult extends Object?>({ TResult maybeWhen<TResult extends Object?>({
TResult Function()? initial, TResult Function()? initial,
TResult Function(String name, String desc, ViewType viewType)? createView, TResult Function(String name, String desc, ViewType viewType)? createView,
TResult Function()? delete,
TResult Function(String newName)? rename,
TResult Function(List<View> views)? didReceiveViews, TResult Function(List<View> views)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -411,6 +670,8 @@ class _$ReceiveViews implements ReceiveViews {
TResult map<TResult extends Object?>({ TResult map<TResult extends Object?>({
required TResult Function(Initial value) initial, required TResult Function(Initial value) initial,
required TResult Function(CreateView value) createView, required TResult Function(CreateView value) createView,
required TResult Function(Delete value) delete,
required TResult Function(Rename value) rename,
required TResult Function(ReceiveViews value) didReceiveViews, required TResult Function(ReceiveViews value) didReceiveViews,
}) { }) {
return didReceiveViews(this); return didReceiveViews(this);
@ -421,6 +682,8 @@ class _$ReceiveViews implements ReceiveViews {
TResult maybeMap<TResult extends Object?>({ TResult maybeMap<TResult extends Object?>({
TResult Function(Initial value)? initial, TResult Function(Initial value)? initial,
TResult Function(CreateView value)? createView, TResult Function(CreateView value)? createView,
TResult Function(Delete value)? delete,
TResult Function(Rename value)? rename,
TResult Function(ReceiveViews value)? didReceiveViews, TResult Function(ReceiveViews value)? didReceiveViews,
required TResult orElse(), required TResult orElse(),
}) { }) {
@ -445,11 +708,13 @@ class _$AppStateTearOff {
const _$AppStateTearOff(); const _$AppStateTearOff();
_AppState call( _AppState call(
{required bool isLoading, {required App app,
required bool isLoading,
required List<View>? views, required List<View>? views,
View? selectedView, View? selectedView,
required Either<Unit, WorkspaceError> successOrFailure}) { required Either<Unit, WorkspaceError> successOrFailure}) {
return _AppState( return _AppState(
app: app,
isLoading: isLoading, isLoading: isLoading,
views: views, views: views,
selectedView: selectedView, selectedView: selectedView,
@ -463,6 +728,7 @@ const $AppState = _$AppStateTearOff();
/// @nodoc /// @nodoc
mixin _$AppState { mixin _$AppState {
App get app => throw _privateConstructorUsedError;
bool get isLoading => throw _privateConstructorUsedError; bool get isLoading => throw _privateConstructorUsedError;
List<View>? get views => throw _privateConstructorUsedError; List<View>? get views => throw _privateConstructorUsedError;
View? get selectedView => throw _privateConstructorUsedError; View? get selectedView => throw _privateConstructorUsedError;
@ -479,7 +745,8 @@ abstract class $AppStateCopyWith<$Res> {
factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) = factory $AppStateCopyWith(AppState value, $Res Function(AppState) then) =
_$AppStateCopyWithImpl<$Res>; _$AppStateCopyWithImpl<$Res>;
$Res call( $Res call(
{bool isLoading, {App app,
bool isLoading,
List<View>? views, List<View>? views,
View? selectedView, View? selectedView,
Either<Unit, WorkspaceError> successOrFailure}); Either<Unit, WorkspaceError> successOrFailure});
@ -495,12 +762,17 @@ class _$AppStateCopyWithImpl<$Res> implements $AppStateCopyWith<$Res> {
@override @override
$Res call({ $Res call({
Object? app = freezed,
Object? isLoading = freezed, Object? isLoading = freezed,
Object? views = freezed, Object? views = freezed,
Object? selectedView = freezed, Object? selectedView = freezed,
Object? successOrFailure = freezed, Object? successOrFailure = freezed,
}) { }) {
return _then(_value.copyWith( return _then(_value.copyWith(
app: app == freezed
? _value.app
: app // ignore: cast_nullable_to_non_nullable
as App,
isLoading: isLoading == freezed isLoading: isLoading == freezed
? _value.isLoading ? _value.isLoading
: isLoading // ignore: cast_nullable_to_non_nullable : isLoading // ignore: cast_nullable_to_non_nullable
@ -527,7 +799,8 @@ abstract class _$AppStateCopyWith<$Res> implements $AppStateCopyWith<$Res> {
__$AppStateCopyWithImpl<$Res>; __$AppStateCopyWithImpl<$Res>;
@override @override
$Res call( $Res call(
{bool isLoading, {App app,
bool isLoading,
List<View>? views, List<View>? views,
View? selectedView, View? selectedView,
Either<Unit, WorkspaceError> successOrFailure}); Either<Unit, WorkspaceError> successOrFailure});
@ -544,12 +817,17 @@ class __$AppStateCopyWithImpl<$Res> extends _$AppStateCopyWithImpl<$Res>
@override @override
$Res call({ $Res call({
Object? app = freezed,
Object? isLoading = freezed, Object? isLoading = freezed,
Object? views = freezed, Object? views = freezed,
Object? selectedView = freezed, Object? selectedView = freezed,
Object? successOrFailure = freezed, Object? successOrFailure = freezed,
}) { }) {
return _then(_AppState( return _then(_AppState(
app: app == freezed
? _value.app
: app // ignore: cast_nullable_to_non_nullable
as App,
isLoading: isLoading == freezed isLoading: isLoading == freezed
? _value.isLoading ? _value.isLoading
: isLoading // ignore: cast_nullable_to_non_nullable : isLoading // ignore: cast_nullable_to_non_nullable
@ -574,11 +852,14 @@ class __$AppStateCopyWithImpl<$Res> extends _$AppStateCopyWithImpl<$Res>
class _$_AppState implements _AppState { class _$_AppState implements _AppState {
const _$_AppState( const _$_AppState(
{required this.isLoading, {required this.app,
required this.isLoading,
required this.views, required this.views,
this.selectedView, this.selectedView,
required this.successOrFailure}); required this.successOrFailure});
@override
final App app;
@override @override
final bool isLoading; final bool isLoading;
@override @override
@ -590,13 +871,15 @@ class _$_AppState implements _AppState {
@override @override
String toString() { String toString() {
return 'AppState(isLoading: $isLoading, views: $views, selectedView: $selectedView, successOrFailure: $successOrFailure)'; return 'AppState(app: $app, isLoading: $isLoading, views: $views, selectedView: $selectedView, successOrFailure: $successOrFailure)';
} }
@override @override
bool operator ==(dynamic other) { bool operator ==(dynamic other) {
return identical(this, other) || return identical(this, other) ||
(other is _AppState && (other is _AppState &&
(identical(other.app, app) ||
const DeepCollectionEquality().equals(other.app, app)) &&
(identical(other.isLoading, isLoading) || (identical(other.isLoading, isLoading) ||
const DeepCollectionEquality() const DeepCollectionEquality()
.equals(other.isLoading, isLoading)) && .equals(other.isLoading, isLoading)) &&
@ -613,6 +896,7 @@ class _$_AppState implements _AppState {
@override @override
int get hashCode => int get hashCode =>
runtimeType.hashCode ^ runtimeType.hashCode ^
const DeepCollectionEquality().hash(app) ^
const DeepCollectionEquality().hash(isLoading) ^ const DeepCollectionEquality().hash(isLoading) ^
const DeepCollectionEquality().hash(views) ^ const DeepCollectionEquality().hash(views) ^
const DeepCollectionEquality().hash(selectedView) ^ const DeepCollectionEquality().hash(selectedView) ^
@ -626,11 +910,14 @@ class _$_AppState implements _AppState {
abstract class _AppState implements AppState { abstract class _AppState implements AppState {
const factory _AppState( const factory _AppState(
{required bool isLoading, {required App app,
required bool isLoading,
required List<View>? views, required List<View>? views,
View? selectedView, View? selectedView,
required Either<Unit, WorkspaceError> successOrFailure}) = _$_AppState; required Either<Unit, WorkspaceError> successOrFailure}) = _$_AppState;
@override
App get app => throw _privateConstructorUsedError;
@override @override
bool get isLoading => throw _privateConstructorUsedError; bool get isLoading => throw _privateConstructorUsedError;
@override @override

View File

@ -8,6 +8,10 @@ abstract class IApp {
Future<Either<List<View>, WorkspaceError>> getViews(); Future<Either<List<View>, WorkspaceError>> getViews();
Future<Either<View, WorkspaceError>> createView({required String name, String? desc, required ViewType viewType}); Future<Either<View, WorkspaceError>> createView({required String name, String? desc, required ViewType viewType});
Future<Either<Unit, WorkspaceError>> delete();
Future<Either<Unit, WorkspaceError>> rename(String newName);
} }
abstract class IAppListenr { abstract class IAppListenr {

View File

@ -1,12 +1,10 @@
import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/protobuf.dart';
import 'package:dartz/dartz.dart'; import 'package:dartz/dartz.dart';
typedef WorkspaceCreateAppCallback = void Function(Either<List<App>, WorkspaceError> appsOrFail); typedef WorkspaceAppsChangedCallback = void Function(Either<List<App>, WorkspaceError> appsOrFail);
typedef WorkspaceUpdatedCallback = void Function(String name, String desc); typedef WorkspaceUpdatedCallback = void Function(String name, String desc);
typedef WorkspaceDeleteAppCallback = void Function(Either<List<App>, WorkspaceError> appsOrFail);
abstract class IWorkspace { abstract class IWorkspace {
Future<Either<App, WorkspaceError>> createApp({required String name, String? desc}); Future<Either<App, WorkspaceError>> createApp({required String name, String? desc});
@ -14,7 +12,7 @@ abstract class IWorkspace {
} }
abstract class IWorkspaceListener { abstract class IWorkspaceListener {
void start({WorkspaceCreateAppCallback? addAppCallback, WorkspaceUpdatedCallback? updatedCallback}); void start({WorkspaceAppsChangedCallback? addAppCallback, WorkspaceUpdatedCallback? updatedCallback});
Future<void> stop(); Future<void> stop();
} }

View File

@ -19,6 +19,7 @@ import 'package:app_flowy/workspace/infrastructure/repos/trash_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/view_repo.dart'; import 'package:app_flowy/workspace/infrastructure/repos/view_repo.dart';
import 'package:app_flowy/workspace/infrastructure/repos/workspace_repo.dart'; import 'package:app_flowy/workspace/infrastructure/repos/workspace_repo.dart';
import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
import 'package:get_it/get_it.dart'; import 'package:get_it/get_it.dart';
@ -77,10 +78,11 @@ class HomeDepsResolver {
(user, _) => MenuUserBloc(getIt<IUser>(param1: user), getIt<IUserListener>(param1: user))); (user, _) => MenuUserBloc(getIt<IUser>(param1: user), getIt<IUserListener>(param1: user)));
// App // App
getIt.registerFactoryParam<AppBloc, String, void>( getIt.registerFactoryParam<AppBloc, App, void>(
(appId, _) => AppBloc( (app, _) => AppBloc(
appManager: getIt<IApp>(param1: appId), app: app,
listener: getIt<IAppListenr>(param1: appId), appManager: getIt<IApp>(param1: app.id),
listener: getIt<IAppListenr>(param1: app.id),
), ),
); );

View File

@ -26,6 +26,16 @@ class IAppImpl extends IApp {
); );
}); });
} }
@override
Future<Either<Unit, workspace.WorkspaceError>> delete() {
return repo.delete();
}
@override
Future<Either<Unit, workspace.WorkspaceError>> rename(String newName) {
return repo.updateApp(name: newName);
}
} }
class IAppListenerhImpl extends IAppListenr { class IAppListenerhImpl extends IAppListenr {

View File

@ -35,7 +35,7 @@ class IWorkspaceListenerImpl extends IWorkspaceListener {
}); });
@override @override
void start({WorkspaceCreateAppCallback? addAppCallback, WorkspaceUpdatedCallback? updatedCallback}) { void start({WorkspaceAppsChangedCallback? addAppCallback, WorkspaceUpdatedCallback? updatedCallback}) {
repo.startListening(createApp: addAppCallback, update: updatedCallback); repo.startListening(createApp: addAppCallback, update: updatedCallback);
} }

View File

@ -6,7 +6,9 @@ import 'package:flowy_log/flowy_log.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart'; import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-dart-notify/subject.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-dart-notify/subject.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/app_create.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_delete.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_query.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/app_query.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/app_update.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/observable.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart'; import 'package:flowy_sdk/protobuf/flowy-workspace/view_create.pb.dart';
@ -21,7 +23,7 @@ class AppRepository {
}); });
Future<Either<App, WorkspaceError>> getAppDesc() { Future<Either<App, WorkspaceError>> getAppDesc() {
final request = QueryAppRequest.create()..appId = appId; final request = QueryAppRequest.create()..appIds.add(appId);
return WorkspaceEventReadApp(request).send(); return WorkspaceEventReadApp(request).send();
} }
@ -37,7 +39,7 @@ class AppRepository {
} }
Future<Either<List<View>, WorkspaceError>> getViews() { Future<Either<List<View>, WorkspaceError>> getViews() {
final request = QueryAppRequest.create()..appId = appId; final request = QueryAppRequest.create()..appIds.add(appId);
return WorkspaceEventReadApp(request).send().then((result) { return WorkspaceEventReadApp(request).send().then((result) {
return result.fold( return result.fold(
@ -46,6 +48,20 @@ class AppRepository {
); );
}); });
} }
Future<Either<Unit, WorkspaceError>> delete() {
final request = QueryAppRequest.create()..appIds.add(appId);
return WorkspaceEventDeleteApp(request).send();
}
Future<Either<Unit, WorkspaceError>> updateApp({String? name}) {
UpdateAppRequest request = UpdateAppRequest.create()..appId = appId;
if (name != null) {
request.name = name;
}
return WorkspaceEventUpdateApp(request).send();
}
} }
class AppListenerRepository { class AppListenerRepository {

View File

@ -64,8 +64,7 @@ class WorkspaceRepo {
class WorkspaceListenerRepo { class WorkspaceListenerRepo {
StreamSubscription<SubscribeObject>? _subscription; StreamSubscription<SubscribeObject>? _subscription;
WorkspaceCreateAppCallback? _createApp; WorkspaceAppsChangedCallback? _appsChanged;
WorkspaceDeleteAppCallback? _deleteApp;
WorkspaceUpdatedCallback? _update; WorkspaceUpdatedCallback? _update;
late WorkspaceNotificationParser _parser; late WorkspaceNotificationParser _parser;
final UserProfile user; final UserProfile user;
@ -77,12 +76,10 @@ class WorkspaceListenerRepo {
}); });
void startListening({ void startListening({
WorkspaceCreateAppCallback? createApp, WorkspaceAppsChangedCallback? appsChanged,
WorkspaceDeleteAppCallback? deleteApp,
WorkspaceUpdatedCallback? update, WorkspaceUpdatedCallback? update,
}) { }) {
_createApp = createApp; _appsChanged = appsChanged;
_deleteApp = deleteApp;
_update = update; _update = update;
_parser = WorkspaceNotificationParser( _parser = WorkspaceNotificationParser(
@ -108,23 +105,13 @@ class WorkspaceListenerRepo {
); );
} }
break; break;
case WorkspaceNotification.WorkspaceCreateApp: case WorkspaceNotification.WorkspaceAppsChanged:
if (_createApp != null) { if (_appsChanged != null) {
result.fold( result.fold(
(payload) => _createApp!( (payload) => _appsChanged!(
left(RepeatedApp.fromBuffer(payload).items), left(RepeatedApp.fromBuffer(payload).items),
), ),
(error) => _createApp!(right(error)), (error) => _appsChanged!(right(error)),
);
}
break;
case WorkspaceNotification.WorkspaceDeleteApp:
if (_deleteApp != null) {
result.fold(
(payload) => _deleteApp!(
left(RepeatedApp.fromBuffer(payload).items),
),
(error) => _deleteApp!(right(error)),
); );
} }
break; break;

View File

@ -1,3 +1,5 @@
import 'package:app_flowy/workspace/domain/edit_action/app_edit.dart';
import 'package:app_flowy/workspace/presentation/widgets/dialogs.dart';
import 'package:expandable/expandable.dart'; import 'package:expandable/expandable.dart';
import 'package:flowy_infra/flowy_icon_data_icons.dart'; import 'package:flowy_infra/flowy_icon_data_icons.dart';
import 'package:flowy_infra/theme.dart'; import 'package:flowy_infra/theme.dart';
@ -10,6 +12,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:app_flowy/workspace/application/app/app_bloc.dart'; import 'package:app_flowy/workspace/application/app/app_bloc.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
import 'package:dartz/dartz.dart';
import '../menu_app.dart'; import '../menu_app.dart';
import 'add_button.dart'; import 'add_button.dart';
@ -67,13 +70,15 @@ class MenuAppHeader extends StatelessWidget {
child: GestureDetector( child: GestureDetector(
behavior: HitTestBehavior.opaque, behavior: HitTestBehavior.opaque,
onTap: () { onTap: () {
// Open the document
ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle(); ExpandableController.of(context, rebuildOnChange: false, required: true)?.toggle();
}, },
onSecondaryTap: () { onSecondaryTap: () {
AppDisclosureActions(onSelected: (action) { final actionList = AppDisclosureActions(onSelected: (action) => _handleAction(context, action));
print(action); actionList.show(
}).show(context, context, anchorDirection: AnchorDirection.bottomWithCenterAligned); context,
context,
anchorDirection: AnchorDirection.bottomWithCenterAligned,
);
}, },
child: FlowyText.medium( child: FlowyText.medium(
app.name, app.name,
@ -90,4 +95,24 @@ class MenuAppHeader extends StatelessWidget {
}, },
).padding(right: MenuAppSizes.headerPadding); ).padding(right: MenuAppSizes.headerPadding);
} }
void _handleAction(BuildContext context, Option<AppDisclosureAction> action) {
action.fold(() {}, (action) {
switch (action) {
case AppDisclosureAction.rename:
TextFieldDialog(
title: 'Rename',
value: context.read<AppBloc>().state.app.name,
confirm: (newValue) {
context.read<AppBloc>().add(AppEvent.rename(newValue));
},
).show(context);
break;
case AppDisclosureAction.delete:
context.read<AppBloc>().add(const AppEvent.delete());
break;
}
});
}
} }

View File

@ -23,7 +23,7 @@ class MenuApp extends MenuItem {
providers: [ providers: [
BlocProvider<AppBloc>( BlocProvider<AppBloc>(
create: (context) { create: (context) {
final appBloc = getIt<AppBloc>(param1: app.id); final appBloc = getIt<AppBloc>(param1: app);
appBloc.add(const AppEvent.initial()); appBloc.add(const AppEvent.initial());
return appBloc; return appBloc;
}, },

View File

@ -119,7 +119,7 @@ class WorkspaceEventCreateApp {
} }
class WorkspaceEventDeleteApp { class WorkspaceEventDeleteApp {
DeleteAppRequest request; QueryAppRequest request;
WorkspaceEventDeleteApp(this.request); WorkspaceEventDeleteApp(this.request);
Future<Either<Unit, WorkspaceError>> send() { Future<Either<Unit, WorkspaceError>> send() {

View File

@ -11,22 +11,17 @@ import 'package:protobuf/protobuf.dart' as $pb;
class QueryAppRequest extends $pb.GeneratedMessage { class QueryAppRequest extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryAppRequest', createEmptyInstance: create) static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'QueryAppRequest', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appId') ..pPS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'appIds')
..aOB(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'isTrash')
..hasRequiredFields = false ..hasRequiredFields = false
; ;
QueryAppRequest._() : super(); QueryAppRequest._() : super();
factory QueryAppRequest({ factory QueryAppRequest({
$core.String? appId, $core.Iterable<$core.String>? appIds,
$core.bool? isTrash,
}) { }) {
final _result = create(); final _result = create();
if (appId != null) { if (appIds != null) {
_result.appId = appId; _result.appIds.addAll(appIds);
}
if (isTrash != null) {
_result.isTrash = isTrash;
} }
return _result; return _result;
} }
@ -52,22 +47,7 @@ class QueryAppRequest extends $pb.GeneratedMessage {
static QueryAppRequest? _defaultInstance; static QueryAppRequest? _defaultInstance;
@$pb.TagNumber(1) @$pb.TagNumber(1)
$core.String get appId => $_getSZ(0); $core.List<$core.String> get appIds => $_getList(0);
@$pb.TagNumber(1)
set appId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasAppId() => $_has(0);
@$pb.TagNumber(1)
void clearAppId() => clearField(1);
@$pb.TagNumber(2)
$core.bool get isTrash => $_getBF(1);
@$pb.TagNumber(2)
set isTrash($core.bool v) { $_setBool(1, v); }
@$pb.TagNumber(2)
$core.bool hasIsTrash() => $_has(1);
@$pb.TagNumber(2)
void clearIsTrash() => clearField(2);
} }
class AppIdentifier extends $pb.GeneratedMessage { class AppIdentifier extends $pb.GeneratedMessage {

View File

@ -12,13 +12,12 @@ import 'dart:typed_data' as $typed_data;
const QueryAppRequest$json = const { const QueryAppRequest$json = const {
'1': 'QueryAppRequest', '1': 'QueryAppRequest',
'2': const [ '2': const [
const {'1': 'app_id', '3': 1, '4': 1, '5': 9, '10': 'appId'}, const {'1': 'app_ids', '3': 1, '4': 3, '5': 9, '10': 'appIds'},
const {'1': 'is_trash', '3': 2, '4': 1, '5': 8, '10': 'isTrash'},
], ],
}; };
/// Descriptor for `QueryAppRequest`. Decode as a `google.protobuf.DescriptorProto`. /// Descriptor for `QueryAppRequest`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List queryAppRequestDescriptor = $convert.base64Decode('Cg9RdWVyeUFwcFJlcXVlc3QSFQoGYXBwX2lkGAEgASgJUgVhcHBJZBIZCghpc190cmFzaBgCIAEoCFIHaXNUcmFzaA=='); final $typed_data.Uint8List queryAppRequestDescriptor = $convert.base64Decode('Cg9RdWVyeUFwcFJlcXVlc3QSFwoHYXBwX2lkcxgBIAMoCVIGYXBwSWRz');
@$core.Deprecated('Use appIdentifierDescriptor instead') @$core.Deprecated('Use appIdentifierDescriptor instead')
const AppIdentifier$json = const { const AppIdentifier$json = const {
'1': 'AppIdentifier', '1': 'AppIdentifier',

View File

@ -14,9 +14,8 @@ class WorkspaceNotification extends $pb.ProtobufEnum {
static const WorkspaceNotification UserCreateWorkspace = WorkspaceNotification._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserCreateWorkspace'); static const WorkspaceNotification UserCreateWorkspace = WorkspaceNotification._(10, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserCreateWorkspace');
static const WorkspaceNotification UserDeleteWorkspace = WorkspaceNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDeleteWorkspace'); static const WorkspaceNotification UserDeleteWorkspace = WorkspaceNotification._(11, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'UserDeleteWorkspace');
static const WorkspaceNotification WorkspaceUpdated = WorkspaceNotification._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceUpdated'); static const WorkspaceNotification WorkspaceUpdated = WorkspaceNotification._(12, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceUpdated');
static const WorkspaceNotification WorkspaceCreateApp = WorkspaceNotification._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceCreateApp'); static const WorkspaceNotification WorkspaceListUpdated = WorkspaceNotification._(13, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceListUpdated');
static const WorkspaceNotification WorkspaceDeleteApp = WorkspaceNotification._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceDeleteApp'); static const WorkspaceNotification WorkspaceAppsChanged = WorkspaceNotification._(14, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceAppsChanged');
static const WorkspaceNotification WorkspaceListUpdated = WorkspaceNotification._(15, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'WorkspaceListUpdated');
static const WorkspaceNotification AppUpdated = WorkspaceNotification._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppUpdated'); static const WorkspaceNotification AppUpdated = WorkspaceNotification._(21, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppUpdated');
static const WorkspaceNotification AppViewsChanged = WorkspaceNotification._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppViewsChanged'); static const WorkspaceNotification AppViewsChanged = WorkspaceNotification._(24, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'AppViewsChanged');
static const WorkspaceNotification ViewUpdated = WorkspaceNotification._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewUpdated'); static const WorkspaceNotification ViewUpdated = WorkspaceNotification._(31, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ViewUpdated');
@ -28,9 +27,8 @@ class WorkspaceNotification extends $pb.ProtobufEnum {
UserCreateWorkspace, UserCreateWorkspace,
UserDeleteWorkspace, UserDeleteWorkspace,
WorkspaceUpdated, WorkspaceUpdated,
WorkspaceCreateApp,
WorkspaceDeleteApp,
WorkspaceListUpdated, WorkspaceListUpdated,
WorkspaceAppsChanged,
AppUpdated, AppUpdated,
AppViewsChanged, AppViewsChanged,
ViewUpdated, ViewUpdated,

View File

@ -16,9 +16,8 @@ const WorkspaceNotification$json = const {
const {'1': 'UserCreateWorkspace', '2': 10}, const {'1': 'UserCreateWorkspace', '2': 10},
const {'1': 'UserDeleteWorkspace', '2': 11}, const {'1': 'UserDeleteWorkspace', '2': 11},
const {'1': 'WorkspaceUpdated', '2': 12}, const {'1': 'WorkspaceUpdated', '2': 12},
const {'1': 'WorkspaceCreateApp', '2': 13}, const {'1': 'WorkspaceListUpdated', '2': 13},
const {'1': 'WorkspaceDeleteApp', '2': 14}, const {'1': 'WorkspaceAppsChanged', '2': 14},
const {'1': 'WorkspaceListUpdated', '2': 15},
const {'1': 'AppUpdated', '2': 21}, const {'1': 'AppUpdated', '2': 21},
const {'1': 'AppViewsChanged', '2': 24}, const {'1': 'AppViewsChanged', '2': 24},
const {'1': 'ViewUpdated', '2': 31}, const {'1': 'ViewUpdated', '2': 31},
@ -28,4 +27,4 @@ const WorkspaceNotification$json = const {
}; };
/// Descriptor for `WorkspaceNotification`. Decode as a `google.protobuf.EnumDescriptorProto`. /// Descriptor for `WorkspaceNotification`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List workspaceNotificationDescriptor = $convert.base64Decode('ChVXb3Jrc3BhY2VOb3RpZmljYXRpb24SCwoHVW5rbm93bhAAEhcKE1VzZXJDcmVhdGVXb3Jrc3BhY2UQChIXChNVc2VyRGVsZXRlV29ya3NwYWNlEAsSFAoQV29ya3NwYWNlVXBkYXRlZBAMEhYKEldvcmtzcGFjZUNyZWF0ZUFwcBANEhYKEldvcmtzcGFjZURlbGV0ZUFwcBAOEhgKFFdvcmtzcGFjZUxpc3RVcGRhdGVkEA8SDgoKQXBwVXBkYXRlZBAVEhMKD0FwcFZpZXdzQ2hhbmdlZBAYEg8KC1ZpZXdVcGRhdGVkEB8SFAoQVXNlclVuYXV0aG9yaXplZBBkEhEKDFRyYXNoVXBkYXRlZBDoBw=='); final $typed_data.Uint8List workspaceNotificationDescriptor = $convert.base64Decode('ChVXb3Jrc3BhY2VOb3RpZmljYXRpb24SCwoHVW5rbm93bhAAEhcKE1VzZXJDcmVhdGVXb3Jrc3BhY2UQChIXChNVc2VyRGVsZXRlV29ya3NwYWNlEAsSFAoQV29ya3NwYWNlVXBkYXRlZBAMEhgKFFdvcmtzcGFjZUxpc3RVcGRhdGVkEA0SGAoUV29ya3NwYWNlQXBwc0NoYW5nZWQQDhIOCgpBcHBVcGRhdGVkEBUSEwoPQXBwVmlld3NDaGFuZ2VkEBgSDwoLVmlld1VwZGF0ZWQQHxIUChBVc2VyVW5hdXRob3JpemVkEGQSEQoMVHJhc2hVcGRhdGVkEOgH');

View File

@ -12,10 +12,12 @@ import 'package:protobuf/protobuf.dart' as $pb;
class TrashType extends $pb.ProtobufEnum { class TrashType extends $pb.ProtobufEnum {
static const TrashType Unknown = TrashType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown'); static const TrashType Unknown = TrashType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'Unknown');
static const TrashType View = TrashType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'View'); static const TrashType View = TrashType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'View');
static const TrashType App = TrashType._(2, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'App');
static const $core.List<TrashType> values = <TrashType> [ static const $core.List<TrashType> values = <TrashType> [
Unknown, Unknown,
View, View,
App,
]; ];
static final $core.Map<$core.int, TrashType> _byValue = $pb.ProtobufEnum.initByValue(values); static final $core.Map<$core.int, TrashType> _byValue = $pb.ProtobufEnum.initByValue(values);

View File

@ -14,11 +14,12 @@ const TrashType$json = const {
'2': const [ '2': const [
const {'1': 'Unknown', '2': 0}, const {'1': 'Unknown', '2': 0},
const {'1': 'View', '2': 1}, const {'1': 'View', '2': 1},
const {'1': 'App', '2': 2},
], ],
}; };
/// Descriptor for `TrashType`. Decode as a `google.protobuf.EnumDescriptorProto`. /// Descriptor for `TrashType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List trashTypeDescriptor = $convert.base64Decode('CglUcmFzaFR5cGUSCwoHVW5rbm93bhAAEggKBFZpZXcQAQ=='); final $typed_data.Uint8List trashTypeDescriptor = $convert.base64Decode('CglUcmFzaFR5cGUSCwoHVW5rbm93bhAAEggKBFZpZXcQARIHCgNBcHAQAg==');
@$core.Deprecated('Use trashIdentifiersDescriptor instead') @$core.Deprecated('Use trashIdentifiersDescriptor instead')
const TrashIdentifiers$json = const { const TrashIdentifiers$json = const {
'1': 'TrashIdentifiers', '1': 'TrashIdentifiers',

View File

@ -46,6 +46,20 @@ impl std::convert::Into<App> for AppTable {
} }
} }
impl std::convert::Into<Trash> for AppTable {
fn into(self) -> Trash {
Trash {
id: self.id.to_string(),
name: self.name,
modified_time: self.modified_time.timestamp(),
create_time: self.create_time.timestamp(),
ty: TrashType::App,
unknown_fields: Default::default(),
cached_size: Default::default(),
}
}
}
#[derive(Debug, Clone, sqlx::FromRow)] #[derive(Debug, Clone, sqlx::FromRow)]
pub struct ViewTable { pub struct ViewTable {
pub(crate) id: uuid::Uuid, pub(crate) id: uuid::Uuid,

View File

@ -4,6 +4,7 @@ use crate::{
sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder}, sqlx_ext::{map_sqlx_error, DBTransaction, SqlBuilder},
}; };
use crate::service::trash::read_trash_ids;
use chrono::Utc; use chrono::Utc;
use flowy_net::errors::{invalid_params, ServerError}; use flowy_net::errors::{invalid_params, ServerError};
use flowy_workspace::{ use flowy_workspace::{
@ -44,6 +45,26 @@ pub(crate) async fn read_app(
app_id: Uuid, app_id: Uuid,
user: &LoggedUser, user: &LoggedUser,
) -> Result<App, ServerError> { ) -> Result<App, ServerError> {
let table = read_app_table(app_id, transaction).await?;
let read_trash_ids = read_trash_ids(user, transaction).await?;
if read_trash_ids.contains(&table.id.to_string()) {
return Err(ServerError::record_not_found());
}
let mut views = RepeatedView::default();
views.set_items(
read_view_belong_to_id(&table.id.to_string(), user, transaction as &mut DBTransaction<'_>)
.await?
.into(),
);
let mut app: App = table.into();
app.set_belongings(views);
Ok(app)
}
pub(crate) async fn read_app_table(app_id: Uuid, transaction: &mut DBTransaction<'_>) -> Result<AppTable, ServerError> {
let (sql, args) = SqlBuilder::select(APP_TABLE) let (sql, args) = SqlBuilder::select(APP_TABLE)
.add_field("*") .add_field("*")
.and_where_eq("id", app_id) .and_where_eq("id", app_id)
@ -54,16 +75,7 @@ pub(crate) async fn read_app(
.await .await
.map_err(map_sqlx_error)?; .map_err(map_sqlx_error)?;
let mut views = RepeatedView::default(); Ok(table)
views.set_items(
read_view_belong_to_id(user, transaction as &mut DBTransaction<'_>, &table.id.to_string())
.await?
.into(),
);
let mut app: App = table.into();
app.set_belongings(views);
Ok(app)
} }
pub(crate) async fn update_app( pub(crate) async fn update_app(

View File

@ -1,6 +1,7 @@
use crate::{ use crate::{
entities::workspace::{TrashTable, TRASH_TABLE}, entities::workspace::{TrashTable, TRASH_TABLE},
service::{ service::{
app::app::{delete_app, read_app_table},
user::LoggedUser, user::LoggedUser,
view::{delete_view, read_view_table}, view::{delete_view, read_view_table},
}, },
@ -82,16 +83,6 @@ pub(crate) async fn delete_trash(
.await .await
.map_err(map_sqlx_error)?; .map_err(map_sqlx_error)?;
match TrashType::from_i32(trash_table.ty) {
None => log::error!("Parser trash type with value: {} failed", trash_table.ty),
Some(ty) => match ty {
TrashType::Unknown => {},
TrashType::View => {
let _ = delete_view(transaction as &mut DBTransaction<'_>, vec![trash_table.id]).await;
},
},
}
let _ = delete_trash_targets( let _ = delete_trash_targets(
transaction as &mut DBTransaction<'_>, transaction as &mut DBTransaction<'_>,
vec![(trash_table.id.clone(), trash_table.ty)], vec![(trash_table.id.clone(), trash_table.ty)],
@ -120,6 +111,9 @@ async fn delete_trash_targets(
TrashType::View => { TrashType::View => {
let _ = delete_view(transaction as &mut DBTransaction<'_>, vec![id]).await; let _ = delete_view(transaction as &mut DBTransaction<'_>, vec![id]).await;
}, },
TrashType::App => {
let _ = delete_app(transaction as &mut DBTransaction<'_>, id).await;
},
}, },
} }
} }
@ -163,6 +157,9 @@ pub(crate) async fn read_trash(
TrashType::View => { TrashType::View => {
trash.push(read_view_table(table.id, transaction).await?.into()); trash.push(read_view_table(table.id, transaction).await?.into());
}, },
TrashType::App => {
trash.push(read_app_table(table.id, transaction).await?.into());
},
}, },
} }
} }

View File

@ -100,7 +100,7 @@ pub(crate) async fn read_view(
let mut views = RepeatedView::default(); let mut views = RepeatedView::default();
views.set_items( views.set_items(
read_view_belong_to_id(&user, transaction, &table.id.to_string()) read_view_belong_to_id(&table.id.to_string(), &user, transaction)
.await? .await?
.into(), .into(),
); );
@ -128,9 +128,9 @@ pub(crate) async fn read_view_table(
// transaction must be commit from caller // transaction must be commit from caller
pub(crate) async fn read_view_belong_to_id<'c>( pub(crate) async fn read_view_belong_to_id<'c>(
id: &str,
user: &LoggedUser, user: &LoggedUser,
transaction: &mut DBTransaction<'_>, transaction: &mut DBTransaction<'_>,
id: &str,
) -> Result<Vec<View>, ServerError> { ) -> Result<Vec<View>, ServerError> {
// TODO: add index for app_table // TODO: add index for app_table
let (sql, args) = SqlBuilder::select(VIEW_TABLE) let (sql, args) = SqlBuilder::select(VIEW_TABLE)

View File

@ -1,6 +1,6 @@
use crate::helper::*; use crate::helper::*;
use flowy_workspace::entities::{ use flowy_workspace::entities::{
app::{AppIdentifier, DeleteAppParams, UpdateAppParams}, app::{AppIdentifier, UpdateAppParams},
trash::{TrashIdentifier, TrashIdentifiers, TrashType}, trash::{TrashIdentifier, TrashIdentifiers, TrashType},
view::{UpdateViewParams, ViewIdentifier}, view::{UpdateViewParams, ViewIdentifier},
workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams}, workspace::{CreateWorkspaceParams, DeleteWorkspaceParams, QueryWorkspaceParams, UpdateWorkspaceParams},
@ -123,7 +123,7 @@ async fn app_update() {
async fn app_delete() { async fn app_delete() {
let test = AppTest::new().await; let test = AppTest::new().await;
let delete_params = DeleteAppParams { let delete_params = AppIdentifier {
app_id: test.app.id.clone(), app_id: test.app.id.clone(),
}; };
test.server.delete_app(delete_params).await; test.server.delete_app(delete_params).await;

View File

@ -95,7 +95,7 @@ impl TestUserServer {
update_app_request(self.user_token(), params, &url).await.unwrap(); update_app_request(self.user_token(), params, &url).await.unwrap();
} }
pub async fn delete_app(&self, params: DeleteAppParams) { pub async fn delete_app(&self, params: AppIdentifier) {
let url = format!("{}/api/app", self.http_addr()); let url = format!("{}/api/app", self.http_addr());
delete_app_request(self.user_token(), params, &url).await.unwrap(); delete_app_request(self.user_token(), params, &url).await.unwrap();
} }

View File

@ -25,8 +25,6 @@ pub fn category_from_str(type_str: &str) -> TypeCategory {
| "RepeatedApp" | "RepeatedApp"
| "UpdateAppRequest" | "UpdateAppRequest"
| "UpdateAppParams" | "UpdateAppParams"
| "DeleteAppRequest"
| "DeleteAppParams"
| "UpdateWorkspaceRequest" | "UpdateWorkspaceRequest"
| "UpdateWorkspaceParams" | "UpdateWorkspaceParams"
| "DeleteWorkspaceRequest" | "DeleteWorkspaceRequest"

View File

@ -172,7 +172,7 @@ pub async fn create_app(sdk: &FlowyTestSDK, name: &str, desc: &str, workspace_id
} }
pub async fn delete_app(sdk: &FlowyTestSDK, app_id: &str) { pub async fn delete_app(sdk: &FlowyTestSDK, app_id: &str) {
let delete_app_request = DeleteAppRequest { let delete_app_request = AppIdentifier {
app_id: app_id.to_string(), app_id: app_id.to_string(),
}; };

View File

@ -1,27 +0,0 @@
use crate::{entities::app::parser::AppId, errors::WorkspaceError};
use flowy_derive::ProtoBuf;
use std::convert::TryInto;
#[derive(Default, ProtoBuf)]
pub struct DeleteAppRequest {
#[pb(index = 1)]
pub app_id: String,
}
#[derive(Default, ProtoBuf, Clone)]
pub struct DeleteAppParams {
#[pb(index = 1)]
pub app_id: String,
}
impl TryInto<DeleteAppParams> for DeleteAppRequest {
type Error = WorkspaceError;
fn try_into(self) -> Result<DeleteAppParams, Self::Error> {
let app_id = AppId::parse(self.app_id)
.map_err(|e| WorkspaceError::app_id().context(e))?
.0;
Ok(DeleteAppParams { app_id })
}
}

View File

@ -5,19 +5,7 @@ use std::convert::TryInto;
#[derive(Default, ProtoBuf, Clone)] #[derive(Default, ProtoBuf, Clone)]
pub struct QueryAppRequest { pub struct QueryAppRequest {
#[pb(index = 1)] #[pb(index = 1)]
pub app_id: String, pub app_ids: Vec<String>,
#[pb(index = 2)]
pub is_trash: bool,
}
impl QueryAppRequest {
pub fn new(app_id: &str) -> Self {
QueryAppRequest {
app_id: app_id.to_string(),
is_trash: false,
}
}
} }
#[derive(ProtoBuf, Default, Clone, Debug)] #[derive(ProtoBuf, Default, Clone, Debug)]
@ -30,7 +18,6 @@ impl AppIdentifier {
pub fn new(app_id: &str) -> Self { pub fn new(app_id: &str) -> Self {
Self { Self {
app_id: app_id.to_string(), app_id: app_id.to_string(),
..Default::default()
} }
} }
} }
@ -39,10 +26,15 @@ impl TryInto<AppIdentifier> for QueryAppRequest {
type Error = WorkspaceError; type Error = WorkspaceError;
fn try_into(self) -> Result<AppIdentifier, Self::Error> { fn try_into(self) -> Result<AppIdentifier, Self::Error> {
let app_id = AppId::parse(self.app_id) debug_assert!(self.app_ids.len() == 1);
.map_err(|e| WorkspaceError::app_id().context(e))? if self.app_ids.len() != 1 {
.0; return Err(WorkspaceError::invalid_view_id().context("The len of app_ids should be equal to 1"));
}
let app_id = self.app_ids.first().unwrap().clone();
let app_id = AppId::parse(app_id)
.map_err(|e| WorkspaceError::invalid_app_id().context(e))?
.0;
Ok(AppIdentifier { app_id }) Ok(AppIdentifier { app_id })
} }
} }

View File

@ -73,7 +73,7 @@ impl TryInto<UpdateAppParams> for UpdateAppRequest {
fn try_into(self) -> Result<UpdateAppParams, Self::Error> { fn try_into(self) -> Result<UpdateAppParams, Self::Error> {
let app_id = AppId::parse(self.app_id) let app_id = AppId::parse(self.app_id)
.map_err(|e| WorkspaceError::app_id().context(e))? .map_err(|e| WorkspaceError::invalid_app_id().context(e))?
.0; .0;
let name = match self.name { let name = match self.name {

View File

@ -2,10 +2,8 @@ pub use app_create::*;
pub use app_update::*; pub use app_update::*;
mod app_create; mod app_create;
mod app_delete;
mod app_query; mod app_query;
mod app_update; mod app_update;
pub mod parser; pub mod parser;
pub use app_delete::*;
pub use app_query::*; pub use app_query::*;

View File

@ -6,6 +6,7 @@ use std::fmt::Formatter;
pub enum TrashType { pub enum TrashType {
Unknown = 0, Unknown = 0,
View = 1, View = 1,
App = 2,
} }
impl std::convert::TryFrom<i32> for TrashType { impl std::convert::TryFrom<i32> for TrashType {
@ -15,6 +16,7 @@ impl std::convert::TryFrom<i32> for TrashType {
match value { match value {
0 => Ok(TrashType::Unknown), 0 => Ok(TrashType::Unknown),
1 => Ok(TrashType::View), 1 => Ok(TrashType::View),
2 => Ok(TrashType::App),
_ => Err(format!("Invalid trash type: {}", value)), _ => Err(format!("Invalid trash type: {}", value)),
} }
} }

View File

@ -98,7 +98,7 @@ impl TryInto<CreateViewParams> for CreateViewRequest {
.0; .0;
let belong_to_id = AppId::parse(self.belong_to_id) let belong_to_id = AppId::parse(self.belong_to_id)
.map_err(|e| WorkspaceError::app_id().context(e))? .map_err(|e| WorkspaceError::invalid_app_id().context(e))?
.0; .0;
let thumbnail = match self.thumbnail { let thumbnail = match self.thumbnail {

View File

@ -42,7 +42,7 @@ impl WorkspaceError {
static_workspace_error!(color_style, ErrorCode::AppColorStyleInvalid); static_workspace_error!(color_style, ErrorCode::AppColorStyleInvalid);
static_workspace_error!(workspace_desc, ErrorCode::WorkspaceDescInvalid); static_workspace_error!(workspace_desc, ErrorCode::WorkspaceDescInvalid);
static_workspace_error!(app_name, ErrorCode::AppNameInvalid); static_workspace_error!(app_name, ErrorCode::AppNameInvalid);
static_workspace_error!(app_id, ErrorCode::AppIdInvalid); static_workspace_error!(invalid_app_id, ErrorCode::AppIdInvalid);
static_workspace_error!(view_name, ErrorCode::ViewNameInvalid); static_workspace_error!(view_name, ErrorCode::ViewNameInvalid);
static_workspace_error!(view_thumbnail, ErrorCode::ViewThumbnailInvalid); static_workspace_error!(view_thumbnail, ErrorCode::ViewThumbnailInvalid);
static_workspace_error!(invalid_view_id, ErrorCode::ViewIdInvalid); static_workspace_error!(invalid_view_id, ErrorCode::ViewIdInvalid);

View File

@ -25,7 +25,7 @@ pub enum WorkspaceEvent {
#[event(input = "CreateAppRequest", output = "App")] #[event(input = "CreateAppRequest", output = "App")]
CreateApp = 101, CreateApp = 101,
#[event(input = "DeleteAppRequest")] #[event(input = "QueryAppRequest")]
DeleteApp = 102, DeleteApp = 102,
#[event(input = "QueryAppRequest", output = "App")] #[event(input = "QueryAppRequest", output = "App")]

View File

@ -1,17 +1,18 @@
use crate::{ use crate::{
entities::app::{ entities::{
App, app::{
AppIdentifier, App,
CreateAppParams, AppIdentifier,
CreateAppRequest, CreateAppParams,
DeleteAppParams, CreateAppRequest,
DeleteAppRequest, QueryAppRequest,
QueryAppRequest, UpdateAppParams,
UpdateAppParams, UpdateAppRequest,
UpdateAppRequest, },
trash::Trash,
}, },
errors::WorkspaceError, errors::WorkspaceError,
services::{AppController, ViewController}, services::{AppController, TrashCan, ViewController},
}; };
use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit}; use flowy_dispatch::prelude::{data_result, Data, DataResult, Unit};
use std::{convert::TryInto, sync::Arc}; use std::{convert::TryInto, sync::Arc};
@ -27,13 +28,20 @@ pub(crate) async fn create_app_handler(
data_result(detail) data_result(detail)
} }
#[tracing::instrument(skip(data, controller))] #[tracing::instrument(skip(data, controller, trash_can))]
pub(crate) async fn delete_app_handler( pub(crate) async fn delete_app_handler(
data: Data<DeleteAppRequest>, data: Data<QueryAppRequest>,
controller: Unit<Arc<AppController>>, controller: Unit<Arc<AppController>>,
trash_can: Unit<Arc<TrashCan>>,
) -> Result<(), WorkspaceError> { ) -> Result<(), WorkspaceError> {
let params: DeleteAppParams = data.into_inner().try_into()?; let params: AppIdentifier = data.into_inner().try_into()?;
let _ = controller.delete_app(&params.app_id).await?; let trash = controller
.read_app_tables(vec![params.app_id])?
.into_iter()
.map(|view_table| view_table.into())
.collect::<Vec<Trash>>();
let _ = trash_can.add(trash).await?;
Ok(()) Ok(())
} }

View File

@ -48,7 +48,12 @@ pub fn mk_workspace(
flowy_document, flowy_document,
)); ));
let app_controller = Arc::new(AppController::new(user.clone(), database.clone(), server.clone())); let app_controller = Arc::new(AppController::new(
user.clone(),
database.clone(),
trash_can.clone(),
server.clone(),
));
let workspace_controller = Arc::new(WorkspaceController::new( let workspace_controller = Arc::new(WorkspaceController::new(
user.clone(), user.clone(),

View File

@ -8,9 +8,8 @@ pub(crate) enum WorkspaceNotification {
UserCreateWorkspace = 10, UserCreateWorkspace = 10,
UserDeleteWorkspace = 11, UserDeleteWorkspace = 11,
WorkspaceUpdated = 12, WorkspaceUpdated = 12,
WorkspaceCreateApp = 13, WorkspaceListUpdated = 13,
WorkspaceDeleteApp = 14, WorkspaceAppsChanged = 14,
WorkspaceListUpdated = 15,
AppUpdated = 21, AppUpdated = 21,
AppViewsChanged = 24, AppViewsChanged = 24,
ViewUpdated = 31, ViewUpdated = 31,

View File

@ -26,8 +26,7 @@
#[derive(PartialEq,Clone,Default)] #[derive(PartialEq,Clone,Default)]
pub struct QueryAppRequest { pub struct QueryAppRequest {
// message fields // message fields
pub app_id: ::std::string::String, pub app_ids: ::protobuf::RepeatedField<::std::string::String>,
pub is_trash: bool,
// special fields // special fields
pub unknown_fields: ::protobuf::UnknownFields, pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize, pub cached_size: ::protobuf::CachedSize,
@ -44,45 +43,29 @@ impl QueryAppRequest {
::std::default::Default::default() ::std::default::Default::default()
} }
// string app_id = 1; // repeated string app_ids = 1;
pub fn get_app_id(&self) -> &str { pub fn get_app_ids(&self) -> &[::std::string::String] {
&self.app_id &self.app_ids
} }
pub fn clear_app_id(&mut self) { pub fn clear_app_ids(&mut self) {
self.app_id.clear(); self.app_ids.clear();
} }
// Param is passed by value, moved // Param is passed by value, moved
pub fn set_app_id(&mut self, v: ::std::string::String) { pub fn set_app_ids(&mut self, v: ::protobuf::RepeatedField<::std::string::String>) {
self.app_id = v; self.app_ids = v;
} }
// Mutable pointer to the field. // Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first. pub fn mut_app_ids(&mut self) -> &mut ::protobuf::RepeatedField<::std::string::String> {
pub fn mut_app_id(&mut self) -> &mut ::std::string::String { &mut self.app_ids
&mut self.app_id
} }
// Take field // Take field
pub fn take_app_id(&mut self) -> ::std::string::String { pub fn take_app_ids(&mut self) -> ::protobuf::RepeatedField<::std::string::String> {
::std::mem::replace(&mut self.app_id, ::std::string::String::new()) ::std::mem::replace(&mut self.app_ids, ::protobuf::RepeatedField::new())
}
// bool is_trash = 2;
pub fn get_is_trash(&self) -> bool {
self.is_trash
}
pub fn clear_is_trash(&mut self) {
self.is_trash = false;
}
// Param is passed by value, moved
pub fn set_is_trash(&mut self, v: bool) {
self.is_trash = v;
} }
} }
@ -96,14 +79,7 @@ impl ::protobuf::Message for QueryAppRequest {
let (field_number, wire_type) = is.read_tag_unpack()?; let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number { match field_number {
1 => { 1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.app_id)?; ::protobuf::rt::read_repeated_string_into(wire_type, is, &mut self.app_ids)?;
},
2 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_bool()?;
self.is_trash = tmp;
}, },
_ => { _ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?; ::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
@ -117,24 +93,18 @@ impl ::protobuf::Message for QueryAppRequest {
#[allow(unused_variables)] #[allow(unused_variables)]
fn compute_size(&self) -> u32 { fn compute_size(&self) -> u32 {
let mut my_size = 0; let mut my_size = 0;
if !self.app_id.is_empty() { for value in &self.app_ids {
my_size += ::protobuf::rt::string_size(1, &self.app_id); my_size += ::protobuf::rt::string_size(1, &value);
} };
if self.is_trash != false {
my_size += 2;
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields()); my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size); self.cached_size.set(my_size);
my_size my_size
} }
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> { fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.app_id.is_empty() { for v in &self.app_ids {
os.write_string(1, &self.app_id)?; os.write_string(1, &v)?;
} };
if self.is_trash != false {
os.write_bool(2, self.is_trash)?;
}
os.write_unknown_fields(self.get_unknown_fields())?; os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(()) ::std::result::Result::Ok(())
} }
@ -173,15 +143,10 @@ impl ::protobuf::Message for QueryAppRequest {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT; static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| { descriptor.get(|| {
let mut fields = ::std::vec::Vec::new(); let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>( fields.push(::protobuf::reflect::accessor::make_repeated_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"app_id", "app_ids",
|m: &QueryAppRequest| { &m.app_id }, |m: &QueryAppRequest| { &m.app_ids },
|m: &mut QueryAppRequest| { &mut m.app_id }, |m: &mut QueryAppRequest| { &mut m.app_ids },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeBool>(
"is_trash",
|m: &QueryAppRequest| { &m.is_trash },
|m: &mut QueryAppRequest| { &mut m.is_trash },
)); ));
::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryAppRequest>( ::protobuf::reflect::MessageDescriptor::new_pb_name::<QueryAppRequest>(
"QueryAppRequest", "QueryAppRequest",
@ -199,8 +164,7 @@ impl ::protobuf::Message for QueryAppRequest {
impl ::protobuf::Clear for QueryAppRequest { impl ::protobuf::Clear for QueryAppRequest {
fn clear(&mut self) { fn clear(&mut self) {
self.app_id.clear(); self.app_ids.clear();
self.is_trash = false;
self.unknown_fields.clear(); self.unknown_fields.clear();
} }
} }
@ -377,21 +341,18 @@ impl ::protobuf::reflect::ProtobufValue for AppIdentifier {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0fapp_query.proto\"C\n\x0fQueryAppRequest\x12\x15\n\x06app_id\x18\ \n\x0fapp_query.proto\"*\n\x0fQueryAppRequest\x12\x17\n\x07app_ids\x18\
\x01\x20\x01(\tR\x05appId\x12\x19\n\x08is_trash\x18\x02\x20\x01(\x08R\ \x01\x20\x03(\tR\x06appIds\"&\n\rAppIdentifier\x12\x15\n\x06app_id\x18\
\x07isTrash\"&\n\rAppIdentifier\x12\x15\n\x06app_id\x18\x01\x20\x01(\tR\ \x01\x20\x01(\tR\x05appIdJ\xbe\x01\n\x06\x12\x04\0\0\x07\x01\n\x08\n\x01\
\x05appIdJ\xe7\x01\n\x06\x12\x04\0\0\x08\x01\n\x08\n\x01\x0c\x12\x03\0\0\ \x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x04\x01\n\n\n\x03\x04\
\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\0\x01\x12\x03\ \0\x01\x12\x03\x02\x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x20\n\
\x02\x08\x17\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04\x16\n\x0c\n\x05\x04\ \x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\n\x05\x04\0\x02\0\
\0\x02\0\x05\x12\x03\x03\x04\n\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\ \x05\x12\x03\x03\r\x13\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x14\x1b\n\
\x0b\x11\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x14\x15\n\x0b\n\x04\x04\ \x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03\x1e\x1f\n\n\n\x02\x04\x01\x12\x04\
\0\x02\x01\x12\x03\x04\x04\x16\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\ \x05\0\x07\x01\n\n\n\x03\x04\x01\x01\x12\x03\x05\x08\x15\n\x0b\n\x04\x04\
\x04\x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x11\n\x0c\n\x05\x04\ \x01\x02\0\x12\x03\x06\x04\x16\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x06\
\0\x02\x01\x03\x12\x03\x04\x14\x15\n\n\n\x02\x04\x01\x12\x04\x06\0\x08\ \x04\n\n\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x06\x0b\x11\n\x0c\n\x05\x04\
\x01\n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x15\n\x0b\n\x04\x04\x01\x02\0\ \x01\x02\0\x03\x12\x03\x06\x14\x15b\x06proto3\
\x12\x03\x07\x04\x16\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\
\x0c\n\x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\x11\n\x0c\n\x05\x04\x01\x02\
\0\x03\x12\x03\x07\x14\x15b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -29,9 +29,8 @@ pub enum WorkspaceNotification {
UserCreateWorkspace = 10, UserCreateWorkspace = 10,
UserDeleteWorkspace = 11, UserDeleteWorkspace = 11,
WorkspaceUpdated = 12, WorkspaceUpdated = 12,
WorkspaceCreateApp = 13, WorkspaceListUpdated = 13,
WorkspaceDeleteApp = 14, WorkspaceAppsChanged = 14,
WorkspaceListUpdated = 15,
AppUpdated = 21, AppUpdated = 21,
AppViewsChanged = 24, AppViewsChanged = 24,
ViewUpdated = 31, ViewUpdated = 31,
@ -50,9 +49,8 @@ impl ::protobuf::ProtobufEnum for WorkspaceNotification {
10 => ::std::option::Option::Some(WorkspaceNotification::UserCreateWorkspace), 10 => ::std::option::Option::Some(WorkspaceNotification::UserCreateWorkspace),
11 => ::std::option::Option::Some(WorkspaceNotification::UserDeleteWorkspace), 11 => ::std::option::Option::Some(WorkspaceNotification::UserDeleteWorkspace),
12 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceUpdated), 12 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceUpdated),
13 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceCreateApp), 13 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceListUpdated),
14 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceDeleteApp), 14 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceAppsChanged),
15 => ::std::option::Option::Some(WorkspaceNotification::WorkspaceListUpdated),
21 => ::std::option::Option::Some(WorkspaceNotification::AppUpdated), 21 => ::std::option::Option::Some(WorkspaceNotification::AppUpdated),
24 => ::std::option::Option::Some(WorkspaceNotification::AppViewsChanged), 24 => ::std::option::Option::Some(WorkspaceNotification::AppViewsChanged),
31 => ::std::option::Option::Some(WorkspaceNotification::ViewUpdated), 31 => ::std::option::Option::Some(WorkspaceNotification::ViewUpdated),
@ -68,9 +66,8 @@ impl ::protobuf::ProtobufEnum for WorkspaceNotification {
WorkspaceNotification::UserCreateWorkspace, WorkspaceNotification::UserCreateWorkspace,
WorkspaceNotification::UserDeleteWorkspace, WorkspaceNotification::UserDeleteWorkspace,
WorkspaceNotification::WorkspaceUpdated, WorkspaceNotification::WorkspaceUpdated,
WorkspaceNotification::WorkspaceCreateApp,
WorkspaceNotification::WorkspaceDeleteApp,
WorkspaceNotification::WorkspaceListUpdated, WorkspaceNotification::WorkspaceListUpdated,
WorkspaceNotification::WorkspaceAppsChanged,
WorkspaceNotification::AppUpdated, WorkspaceNotification::AppUpdated,
WorkspaceNotification::AppViewsChanged, WorkspaceNotification::AppViewsChanged,
WorkspaceNotification::ViewUpdated, WorkspaceNotification::ViewUpdated,
@ -104,40 +101,37 @@ impl ::protobuf::reflect::ProtobufValue for WorkspaceNotification {
} }
static file_descriptor_proto_data: &'static [u8] = b"\ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x10observable.proto*\x95\x02\n\x15WorkspaceNotification\x12\x0b\n\x07\ \n\x10observable.proto*\xff\x01\n\x15WorkspaceNotification\x12\x0b\n\x07\
Unknown\x10\0\x12\x17\n\x13UserCreateWorkspace\x10\n\x12\x17\n\x13UserDe\ Unknown\x10\0\x12\x17\n\x13UserCreateWorkspace\x10\n\x12\x17\n\x13UserDe\
leteWorkspace\x10\x0b\x12\x14\n\x10WorkspaceUpdated\x10\x0c\x12\x16\n\ leteWorkspace\x10\x0b\x12\x14\n\x10WorkspaceUpdated\x10\x0c\x12\x18\n\
\x12WorkspaceCreateApp\x10\r\x12\x16\n\x12WorkspaceDeleteApp\x10\x0e\x12\ \x14WorkspaceListUpdated\x10\r\x12\x18\n\x14WorkspaceAppsChanged\x10\x0e\
\x18\n\x14WorkspaceListUpdated\x10\x0f\x12\x0e\n\nAppUpdated\x10\x15\x12\ \x12\x0e\n\nAppUpdated\x10\x15\x12\x13\n\x0fAppViewsChanged\x10\x18\x12\
\x13\n\x0fAppViewsChanged\x10\x18\x12\x0f\n\x0bViewUpdated\x10\x1f\x12\ \x0f\n\x0bViewUpdated\x10\x1f\x12\x14\n\x10UserUnauthorized\x10d\x12\x11\
\x14\n\x10UserUnauthorized\x10d\x12\x11\n\x0cTrashUpdated\x10\xe8\x07J\ \n\x0cTrashUpdated\x10\xe8\x07J\xed\x03\n\x06\x12\x04\0\0\x0e\x01\n\x08\
\x96\x04\n\x06\x12\x04\0\0\x0f\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\ \n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x05\0\x12\x04\x02\0\x0e\x01\n\n\n\
\x02\x05\0\x12\x04\x02\0\x0f\x01\n\n\n\x03\x05\0\x01\x12\x03\x02\x05\x1a\ \x03\x05\0\x01\x12\x03\x02\x05\x1a\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\
\n\x0b\n\x04\x05\0\x02\0\x12\x03\x03\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\ \x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x03\x04\x0b\n\x0c\n\x05\x05\
\x12\x03\x03\x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x03\x0e\x0f\n\ \0\x02\0\x02\x12\x03\x03\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\
\x0b\n\x04\x05\0\x02\x01\x12\x03\x04\x04\x1d\n\x0c\n\x05\x05\0\x02\x01\ \x04\x1d\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x04\x04\x17\n\x0c\n\x05\
\x01\x12\x03\x04\x04\x17\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x04\x1a\ \x05\0\x02\x01\x02\x12\x03\x04\x1a\x1c\n\x0b\n\x04\x05\0\x02\x02\x12\x03\
\x1c\n\x0b\n\x04\x05\0\x02\x02\x12\x03\x05\x04\x1d\n\x0c\n\x05\x05\0\x02\ \x05\x04\x1d\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\x05\x04\x17\n\x0c\n\
\x02\x01\x12\x03\x05\x04\x17\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x05\ \x05\x05\0\x02\x02\x02\x12\x03\x05\x1a\x1c\n\x0b\n\x04\x05\0\x02\x03\x12\
\x1a\x1c\n\x0b\n\x04\x05\0\x02\x03\x12\x03\x06\x04\x1a\n\x0c\n\x05\x05\0\ \x03\x06\x04\x1a\n\x0c\n\x05\x05\0\x02\x03\x01\x12\x03\x06\x04\x14\n\x0c\
\x02\x03\x01\x12\x03\x06\x04\x14\n\x0c\n\x05\x05\0\x02\x03\x02\x12\x03\ \n\x05\x05\0\x02\x03\x02\x12\x03\x06\x17\x19\n\x0b\n\x04\x05\0\x02\x04\
\x06\x17\x19\n\x0b\n\x04\x05\0\x02\x04\x12\x03\x07\x04\x1c\n\x0c\n\x05\ \x12\x03\x07\x04\x1e\n\x0c\n\x05\x05\0\x02\x04\x01\x12\x03\x07\x04\x18\n\
\x05\0\x02\x04\x01\x12\x03\x07\x04\x16\n\x0c\n\x05\x05\0\x02\x04\x02\x12\ \x0c\n\x05\x05\0\x02\x04\x02\x12\x03\x07\x1b\x1d\n\x0b\n\x04\x05\0\x02\
\x03\x07\x19\x1b\n\x0b\n\x04\x05\0\x02\x05\x12\x03\x08\x04\x1c\n\x0c\n\ \x05\x12\x03\x08\x04\x1e\n\x0c\n\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\
\x05\x05\0\x02\x05\x01\x12\x03\x08\x04\x16\n\x0c\n\x05\x05\0\x02\x05\x02\ \x18\n\x0c\n\x05\x05\0\x02\x05\x02\x12\x03\x08\x1b\x1d\n\x0b\n\x04\x05\0\
\x12\x03\x08\x19\x1b\n\x0b\n\x04\x05\0\x02\x06\x12\x03\t\x04\x1e\n\x0c\n\ \x02\x06\x12\x03\t\x04\x14\n\x0c\n\x05\x05\0\x02\x06\x01\x12\x03\t\x04\
\x05\x05\0\x02\x06\x01\x12\x03\t\x04\x18\n\x0c\n\x05\x05\0\x02\x06\x02\ \x0e\n\x0c\n\x05\x05\0\x02\x06\x02\x12\x03\t\x11\x13\n\x0b\n\x04\x05\0\
\x12\x03\t\x1b\x1d\n\x0b\n\x04\x05\0\x02\x07\x12\x03\n\x04\x14\n\x0c\n\ \x02\x07\x12\x03\n\x04\x19\n\x0c\n\x05\x05\0\x02\x07\x01\x12\x03\n\x04\
\x05\x05\0\x02\x07\x01\x12\x03\n\x04\x0e\n\x0c\n\x05\x05\0\x02\x07\x02\ \x13\n\x0c\n\x05\x05\0\x02\x07\x02\x12\x03\n\x16\x18\n\x0b\n\x04\x05\0\
\x12\x03\n\x11\x13\n\x0b\n\x04\x05\0\x02\x08\x12\x03\x0b\x04\x19\n\x0c\n\ \x02\x08\x12\x03\x0b\x04\x15\n\x0c\n\x05\x05\0\x02\x08\x01\x12\x03\x0b\
\x05\x05\0\x02\x08\x01\x12\x03\x0b\x04\x13\n\x0c\n\x05\x05\0\x02\x08\x02\ \x04\x0f\n\x0c\n\x05\x05\0\x02\x08\x02\x12\x03\x0b\x12\x14\n\x0b\n\x04\
\x12\x03\x0b\x16\x18\n\x0b\n\x04\x05\0\x02\t\x12\x03\x0c\x04\x15\n\x0c\n\ \x05\0\x02\t\x12\x03\x0c\x04\x1b\n\x0c\n\x05\x05\0\x02\t\x01\x12\x03\x0c\
\x05\x05\0\x02\t\x01\x12\x03\x0c\x04\x0f\n\x0c\n\x05\x05\0\x02\t\x02\x12\ \x04\x14\n\x0c\n\x05\x05\0\x02\t\x02\x12\x03\x0c\x17\x1a\n\x0b\n\x04\x05\
\x03\x0c\x12\x14\n\x0b\n\x04\x05\0\x02\n\x12\x03\r\x04\x1b\n\x0c\n\x05\ \0\x02\n\x12\x03\r\x04\x18\n\x0c\n\x05\x05\0\x02\n\x01\x12\x03\r\x04\x10\
\x05\0\x02\n\x01\x12\x03\r\x04\x14\n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\ \n\x0c\n\x05\x05\0\x02\n\x02\x12\x03\r\x13\x17b\x06proto3\
\x17\x1a\n\x0b\n\x04\x05\0\x02\x0b\x12\x03\x0e\x04\x18\n\x0c\n\x05\x05\0\
\x02\x0b\x01\x12\x03\x0e\x04\x10\n\x0c\n\x05\x05\0\x02\x0b\x02\x12\x03\
\x0e\x13\x17b\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -886,6 +886,7 @@ impl ::protobuf::reflect::ProtobufValue for RepeatedTrash {
pub enum TrashType { pub enum TrashType {
Unknown = 0, Unknown = 0,
View = 1, View = 1,
App = 2,
} }
impl ::protobuf::ProtobufEnum for TrashType { impl ::protobuf::ProtobufEnum for TrashType {
@ -897,6 +898,7 @@ impl ::protobuf::ProtobufEnum for TrashType {
match value { match value {
0 => ::std::option::Option::Some(TrashType::Unknown), 0 => ::std::option::Option::Some(TrashType::Unknown),
1 => ::std::option::Option::Some(TrashType::View), 1 => ::std::option::Option::Some(TrashType::View),
2 => ::std::option::Option::Some(TrashType::App),
_ => ::std::option::Option::None _ => ::std::option::Option::None
} }
} }
@ -905,6 +907,7 @@ impl ::protobuf::ProtobufEnum for TrashType {
static values: &'static [TrashType] = &[ static values: &'static [TrashType] = &[
TrashType::Unknown, TrashType::Unknown,
TrashType::View, TrashType::View,
TrashType::App,
]; ];
values values
} }
@ -942,47 +945,49 @@ static file_descriptor_proto_data: &'static [u8] = b"\
me\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcreate_time\x18\ me\x18\x03\x20\x01(\x03R\x0cmodifiedTime\x12\x1f\n\x0bcreate_time\x18\
\x04\x20\x01(\x03R\ncreateTime\x12\x1a\n\x02ty\x18\x05\x20\x01(\x0e2\n.T\ \x04\x20\x01(\x03R\ncreateTime\x12\x1a\n\x02ty\x18\x05\x20\x01(\x0e2\n.T\
rashTypeR\x02ty\"-\n\rRepeatedTrash\x12\x1c\n\x05items\x18\x01\x20\x03(\ rashTypeR\x02ty\"-\n\rRepeatedTrash\x12\x1c\n\x05items\x18\x01\x20\x03(\
\x0b2\x06.TrashR\x05items*\"\n\tTrashType\x12\x0b\n\x07Unknown\x10\0\x12\ \x0b2\x06.TrashR\x05items*+\n\tTrashType\x12\x0b\n\x07Unknown\x10\0\x12\
\x08\n\x04View\x10\x01J\x9e\x06\n\x06\x12\x04\0\0\x17\x01\n\x08\n\x01\ \x08\n\x04View\x10\x01\x12\x07\n\x03App\x10\x02J\xc7\x06\n\x06\x12\x04\0\
\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\x05\x01\n\n\n\x03\x04\ \0\x18\x01\n\x08\n\x01\x0c\x12\x03\0\0\x12\n\n\n\x02\x04\0\x12\x04\x02\0\
\0\x01\x12\x03\x02\x08\x18\n\x0b\n\x04\x04\0\x02\0\x12\x03\x03\x04'\n\ \x05\x01\n\n\n\x03\x04\0\x01\x12\x03\x02\x08\x18\n\x0b\n\x04\x04\0\x02\0\
\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\n\x05\x04\0\x02\0\ \x12\x03\x03\x04'\n\x0c\n\x05\x04\0\x02\0\x04\x12\x03\x03\x04\x0c\n\x0c\
\x06\x12\x03\x03\r\x1c\n\x0c\n\x05\x04\0\x02\0\x01\x12\x03\x03\x1d\"\n\ \n\x05\x04\0\x02\0\x06\x12\x03\x03\r\x1c\n\x0c\n\x05\x04\0\x02\0\x01\x12\
\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03%&\n\x0b\n\x04\x04\0\x02\x01\x12\ \x03\x03\x1d\"\n\x0c\n\x05\x04\0\x02\0\x03\x12\x03\x03%&\n\x0b\n\x04\x04\
\x03\x04\x04\x18\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\x04\x08\n\x0c\ \0\x02\x01\x12\x03\x04\x04\x18\n\x0c\n\x05\x04\0\x02\x01\x05\x12\x03\x04\
\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x13\n\x0c\n\x05\x04\0\x02\x01\x03\ \x04\x08\n\x0c\n\x05\x04\0\x02\x01\x01\x12\x03\x04\t\x13\n\x0c\n\x05\x04\
\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\x04\x06\0\t\x01\n\n\n\x03\x04\ \0\x02\x01\x03\x12\x03\x04\x16\x17\n\n\n\x02\x04\x01\x12\x04\x06\0\t\x01\
\x01\x01\x12\x03\x06\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\x03\x07\x04\ \n\n\n\x03\x04\x01\x01\x12\x03\x06\x08\x17\n\x0b\n\x04\x04\x01\x02\0\x12\
\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\x05\x04\x01\ \x03\x07\x04\x12\n\x0c\n\x05\x04\x01\x02\0\x05\x12\x03\x07\x04\n\n\x0c\n\
\x02\0\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\x12\x03\x07\ \x05\x04\x01\x02\0\x01\x12\x03\x07\x0b\r\n\x0c\n\x05\x04\x01\x02\0\x03\
\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\x15\n\x0c\n\x05\x04\ \x12\x03\x07\x10\x11\n\x0b\n\x04\x04\x01\x02\x01\x12\x03\x08\x04\x15\n\
\x01\x02\x01\x06\x12\x03\x08\x04\r\n\x0c\n\x05\x04\x01\x02\x01\x01\x12\ \x0c\n\x05\x04\x01\x02\x01\x06\x12\x03\x08\x04\r\n\x0c\n\x05\x04\x01\x02\
\x03\x08\x0e\x10\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x08\x13\x14\n\n\ \x01\x01\x12\x03\x08\x0e\x10\n\x0c\n\x05\x04\x01\x02\x01\x03\x12\x03\x08\
\n\x02\x04\x02\x12\x04\n\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\x03\n\x08\r\ \x13\x14\n\n\n\x02\x04\x02\x12\x04\n\0\x10\x01\n\n\n\x03\x04\x02\x01\x12\
\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\x04\x12\n\x0c\n\x05\x04\x02\x02\0\ \x03\n\x08\r\n\x0b\n\x04\x04\x02\x02\0\x12\x03\x0b\x04\x12\n\x0c\n\x05\
\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\x03\x0b\x0b\r\n\ \x04\x02\x02\0\x05\x12\x03\x0b\x04\n\n\x0c\n\x05\x04\x02\x02\0\x01\x12\
\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0b\x10\x11\n\x0b\n\x04\x04\x02\x02\ \x03\x0b\x0b\r\n\x0c\n\x05\x04\x02\x02\0\x03\x12\x03\x0b\x10\x11\n\x0b\n\
\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\x12\x03\x0c\x04\ \x04\x04\x02\x02\x01\x12\x03\x0c\x04\x14\n\x0c\n\x05\x04\x02\x02\x01\x05\
\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x0c\x0b\x0f\n\x0c\n\x05\x04\ \x12\x03\x0c\x04\n\n\x0c\n\x05\x04\x02\x02\x01\x01\x12\x03\x0c\x0b\x0f\n\
\x02\x02\x01\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x02\x02\x02\x12\x03\ \x0c\n\x05\x04\x02\x02\x01\x03\x12\x03\x0c\x12\x13\n\x0b\n\x04\x04\x02\
\r\x04\x1c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\r\x04\t\n\x0c\n\x05\ \x02\x02\x12\x03\r\x04\x1c\n\x0c\n\x05\x04\x02\x02\x02\x05\x12\x03\r\x04\
\x04\x02\x02\x02\x01\x12\x03\r\n\x17\n\x0c\n\x05\x04\x02\x02\x02\x03\x12\ \t\n\x0c\n\x05\x04\x02\x02\x02\x01\x12\x03\r\n\x17\n\x0c\n\x05\x04\x02\
\x03\r\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x0e\x04\x1a\n\x0c\n\ \x02\x02\x03\x12\x03\r\x1a\x1b\n\x0b\n\x04\x04\x02\x02\x03\x12\x03\x0e\
\x05\x04\x02\x02\x03\x05\x12\x03\x0e\x04\t\n\x0c\n\x05\x04\x02\x02\x03\ \x04\x1a\n\x0c\n\x05\x04\x02\x02\x03\x05\x12\x03\x0e\x04\t\n\x0c\n\x05\
\x01\x12\x03\x0e\n\x15\n\x0c\n\x05\x04\x02\x02\x03\x03\x12\x03\x0e\x18\ \x04\x02\x02\x03\x01\x12\x03\x0e\n\x15\n\x0c\n\x05\x04\x02\x02\x03\x03\
\x19\n\x0b\n\x04\x04\x02\x02\x04\x12\x03\x0f\x04\x15\n\x0c\n\x05\x04\x02\ \x12\x03\x0e\x18\x19\n\x0b\n\x04\x04\x02\x02\x04\x12\x03\x0f\x04\x15\n\
\x02\x04\x06\x12\x03\x0f\x04\r\n\x0c\n\x05\x04\x02\x02\x04\x01\x12\x03\ \x0c\n\x05\x04\x02\x02\x04\x06\x12\x03\x0f\x04\r\n\x0c\n\x05\x04\x02\x02\
\x0f\x0e\x10\n\x0c\n\x05\x04\x02\x02\x04\x03\x12\x03\x0f\x13\x14\n\n\n\ \x04\x01\x12\x03\x0f\x0e\x10\n\x0c\n\x05\x04\x02\x02\x04\x03\x12\x03\x0f\
\x02\x04\x03\x12\x04\x11\0\x13\x01\n\n\n\x03\x04\x03\x01\x12\x03\x11\x08\ \x13\x14\n\n\n\x02\x04\x03\x12\x04\x11\0\x13\x01\n\n\n\x03\x04\x03\x01\
\x15\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x1d\n\x0c\n\x05\x04\x03\ \x12\x03\x11\x08\x15\n\x0b\n\x04\x04\x03\x02\0\x12\x03\x12\x04\x1d\n\x0c\
\x02\0\x04\x12\x03\x12\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\x06\x12\x03\x12\ \n\x05\x04\x03\x02\0\x04\x12\x03\x12\x04\x0c\n\x0c\n\x05\x04\x03\x02\0\
\r\x12\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x13\x18\n\x0c\n\x05\x04\ \x06\x12\x03\x12\r\x12\n\x0c\n\x05\x04\x03\x02\0\x01\x12\x03\x12\x13\x18\
\x03\x02\0\x03\x12\x03\x12\x1b\x1c\n\n\n\x02\x05\0\x12\x04\x14\0\x17\x01\ \n\x0c\n\x05\x04\x03\x02\0\x03\x12\x03\x12\x1b\x1c\n\n\n\x02\x05\0\x12\
\n\n\n\x03\x05\0\x01\x12\x03\x14\x05\x0e\n\x0b\n\x04\x05\0\x02\0\x12\x03\ \x04\x14\0\x18\x01\n\n\n\x03\x05\0\x01\x12\x03\x14\x05\x0e\n\x0b\n\x04\
\x15\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x15\x04\x0b\n\x0c\n\x05\ \x05\0\x02\0\x12\x03\x15\x04\x10\n\x0c\n\x05\x05\0\x02\0\x01\x12\x03\x15\
\x05\0\x02\0\x02\x12\x03\x15\x0e\x0f\n\x0b\n\x04\x05\0\x02\x01\x12\x03\ \x04\x0b\n\x0c\n\x05\x05\0\x02\0\x02\x12\x03\x15\x0e\x0f\n\x0b\n\x04\x05\
\x16\x04\r\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x16\x04\x08\n\x0c\n\x05\ \0\x02\x01\x12\x03\x16\x04\r\n\x0c\n\x05\x05\0\x02\x01\x01\x12\x03\x16\
\x05\0\x02\x01\x02\x12\x03\x16\x0b\x0cb\x06proto3\ \x04\x08\n\x0c\n\x05\x05\0\x02\x01\x02\x12\x03\x16\x0b\x0c\n\x0b\n\x04\
\x05\0\x02\x02\x12\x03\x17\x04\x0c\n\x0c\n\x05\x05\0\x02\x02\x01\x12\x03\
\x17\x04\x07\n\x0c\n\x05\x05\0\x02\x02\x02\x12\x03\x17\n\x0bb\x06proto3\
"; ";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT; static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -1,8 +1,7 @@
syntax = "proto3"; syntax = "proto3";
message QueryAppRequest { message QueryAppRequest {
string app_id = 1; repeated string app_ids = 1;
bool is_trash = 2;
} }
message AppIdentifier { message AppIdentifier {
string app_id = 1; string app_id = 1;

View File

@ -5,9 +5,8 @@ enum WorkspaceNotification {
UserCreateWorkspace = 10; UserCreateWorkspace = 10;
UserDeleteWorkspace = 11; UserDeleteWorkspace = 11;
WorkspaceUpdated = 12; WorkspaceUpdated = 12;
WorkspaceCreateApp = 13; WorkspaceListUpdated = 13;
WorkspaceDeleteApp = 14; WorkspaceAppsChanged = 14;
WorkspaceListUpdated = 15;
AppUpdated = 21; AppUpdated = 21;
AppViewsChanged = 24; AppViewsChanged = 24;
ViewUpdated = 31; ViewUpdated = 31;

View File

@ -21,4 +21,5 @@ message RepeatedTrash {
enum TrashType { enum TrashType {
Unknown = 0; Unknown = 0;
View = 1; View = 1;
App = 2;
} }

View File

@ -1,25 +1,43 @@
use crate::{ use crate::{
entities::app::{App, CreateAppParams, *}, entities::{
app::{App, CreateAppParams, *},
trash::TrashType,
},
errors::*, errors::*,
module::{WorkspaceDatabase, WorkspaceUser}, module::{WorkspaceDatabase, WorkspaceUser},
notify::*, notify::*,
services::{helper::spawn, server::Server}, services::{helper::spawn, server::Server, TrashCan, TrashEvent},
sql_tables::app::{AppTable, AppTableChangeset, AppTableSql}, sql_tables::app::{AppTable, AppTableChangeset, AppTableSql},
}; };
use flowy_database::SqliteConnection; use flowy_database::SqliteConnection;
use futures::{FutureExt, StreamExt};
use std::sync::Arc; use std::{collections::HashSet, sync::Arc};
pub(crate) struct AppController { pub(crate) struct AppController {
user: Arc<dyn WorkspaceUser>, user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>, database: Arc<dyn WorkspaceDatabase>,
trash_can: Arc<TrashCan>,
server: Server, server: Server,
} }
impl AppController { impl AppController {
pub(crate) fn new(user: Arc<dyn WorkspaceUser>, database: Arc<dyn WorkspaceDatabase>, server: Server) -> Self { pub(crate) fn new(
Self { user, database, server } user: Arc<dyn WorkspaceUser>,
database: Arc<dyn WorkspaceDatabase>,
trash_can: Arc<TrashCan>,
server: Server,
) -> Self {
Self {
user,
database,
trash_can,
server,
}
}
pub fn init(&self) -> Result<(), WorkspaceError> {
self.listen_trash_can_event();
Ok(())
} }
#[tracing::instrument(level = "debug", skip(self), err)] #[tracing::instrument(level = "debug", skip(self), err)]
@ -29,10 +47,7 @@ impl AppController {
conn.immediate_transaction::<_, WorkspaceError, _>(|| { conn.immediate_transaction::<_, WorkspaceError, _>(|| {
let _ = self.save_app(app.clone(), &*conn)?; let _ = self.save_app(app.clone(), &*conn)?;
let apps = self.read_local_apps(&app.workspace_id, &*conn)?; let _ = notify_app_num_changed(&app.workspace_id, self.trash_can.clone(), conn)?;
send_dart_notification(&app.workspace_id, WorkspaceNotification::WorkspaceCreateApp)
.payload(apps)
.send();
Ok(()) Ok(())
})?; })?;
@ -46,33 +61,18 @@ impl AppController {
} }
pub(crate) async fn read_app(&self, params: AppIdentifier) -> Result<App, WorkspaceError> { pub(crate) async fn read_app(&self, params: AppIdentifier) -> Result<App, WorkspaceError> {
let app_table = AppTableSql::read_app(&params.app_id, &*self.database.db_connection()?)?; let conn = self.database.db_connection()?;
let app_table = AppTableSql::read_app(&params.app_id, &*conn)?;
let trash_ids = self.trash_can.trash_ids(&conn)?;
if trash_ids.contains(&app_table.id) {
return Err(WorkspaceError::record_not_found());
}
let _ = self.read_app_on_server(params)?; let _ = self.read_app_on_server(params)?;
Ok(app_table.into()) Ok(app_table.into())
} }
#[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn delete_app(&self, app_id: &str) -> Result<(), WorkspaceError> {
let conn = &*self.database.db_connection()?;
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
let app = AppTableSql::delete_app(app_id, &*conn)?;
let apps = self.read_local_apps(&app.workspace_id, &*conn)?;
send_dart_notification(&app.workspace_id, WorkspaceNotification::WorkspaceDeleteApp)
.payload(apps)
.send();
Ok(())
})?;
let _ = self.delete_app_on_server(app_id);
Ok(())
}
fn read_local_apps(&self, workspace_id: &str, conn: &SqliteConnection) -> Result<RepeatedApp, WorkspaceError> {
let app_tables = AppTableSql::read_apps(workspace_id, false, conn)?;
let apps = app_tables.into_iter().map(|table| table.into()).collect::<Vec<App>>();
Ok(RepeatedApp { items: apps })
}
pub(crate) async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> { pub(crate) async fn update_app(&self, params: UpdateAppParams) -> Result<(), WorkspaceError> {
let changeset = AppTableChangeset::new(params.clone()); let changeset = AppTableChangeset::new(params.clone());
let app_id = changeset.id.clone(); let app_id = changeset.id.clone();
@ -89,6 +89,19 @@ impl AppController {
let _ = self.update_app_on_server(params)?; let _ = self.update_app_on_server(params)?;
Ok(()) Ok(())
} }
pub(crate) fn read_app_tables(&self, ids: Vec<String>) -> Result<Vec<AppTable>, WorkspaceError> {
let conn = &*self.database.db_connection()?;
let mut app_tables = vec![];
conn.immediate_transaction::<_, WorkspaceError, _>(|| {
for app_id in ids {
app_tables.push(AppTableSql::read_app(&app_id, conn)?);
}
Ok(())
})?;
Ok(app_tables)
}
} }
impl AppController { impl AppController {
@ -115,37 +128,6 @@ impl AppController {
Ok(()) Ok(())
} }
#[tracing::instrument(level = "debug", skip(self), err)]
fn delete_app_on_server(&self, app_id: &str) -> Result<(), WorkspaceError> {
let token = self.user.token()?;
let server = self.server.clone();
let params = DeleteAppParams {
app_id: app_id.to_string(),
};
spawn(async move {
match server.delete_app(&token, params).await {
Ok(_) => {},
Err(e) => {
// TODO: retry?
log::error!("Delete app failed: {:?}", e);
},
}
});
// let action = RetryAction::new(self.server.clone(), self.user.clone(), move
// |token, server| { let params = params.clone();
// async move {
// match server.delete_app(&token, params).await {
// Ok(_) => {},
// Err(e) => log::error!("Delete app failed: {:?}", e),
// }
// Ok::<(), WorkspaceError>(())
// }
// });
//
// spawn_retry(500, 3, action);
Ok(())
}
#[tracing::instrument(level = "debug", skip(self), err)] #[tracing::instrument(level = "debug", skip(self), err)]
fn read_app_on_server(&self, params: AppIdentifier) -> Result<(), WorkspaceError> { fn read_app_on_server(&self, params: AppIdentifier) -> Result<(), WorkspaceError> {
let token = self.user.token()?; let token = self.user.token()?;
@ -175,4 +157,137 @@ impl AppController {
}); });
Ok(()) Ok(())
} }
fn listen_trash_can_event(&self) {
let mut rx = self.trash_can.subscribe();
let database = self.database.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 {
match result {
Ok(event) => event.select(TrashType::App),
Err(_e) => None,
}
}));
match stream.next().await {
Some(event) => handle_trash_event(database.clone(), trash_can.clone(), event).await,
None => {},
}
}
});
}
} }
async fn handle_trash_event(database: Arc<dyn WorkspaceDatabase>, trash_can: Arc<TrashCan>, event: TrashEvent) {
let db_result = database.db_connection();
match event {
TrashEvent::NewTrash(identifiers, ret) | TrashEvent::Putback(identifiers, ret) => {
let result = || {
let conn = &*db_result?;
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
for identifier in identifiers.items {
let app_table = AppTableSql::read_app(&identifier.id, conn)?;
let _ = notify_app_num_changed(&app_table.workspace_id, trash_can.clone(), conn)?;
}
Ok(())
})?;
Ok::<(), WorkspaceError>(())
};
let _ = ret.send(result()).await;
},
TrashEvent::Delete(identifiers, ret) => {
let result = || {
let conn = &*db_result?;
let _ = conn.immediate_transaction::<_, WorkspaceError, _>(|| {
let mut notify_ids = HashSet::new();
for identifier in identifiers.items {
let app_table = AppTableSql::read_app(&identifier.id, conn)?;
let _ = AppTableSql::delete_app(&identifier.id, conn)?;
notify_ids.insert(app_table.workspace_id);
}
for notify_id in notify_ids {
let _ = notify_app_num_changed(&notify_id, trash_can.clone(), conn)?;
}
Ok(())
})?;
Ok::<(), WorkspaceError>(())
};
let _ = ret.send(result()).await;
},
}
}
#[tracing::instrument(skip(workspace_id, trash_can, conn), err)]
fn notify_app_num_changed(
workspace_id: &str,
trash_can: Arc<TrashCan>,
conn: &SqliteConnection,
) -> WorkspaceResult<()> {
let repeated_app = read_local_workspace_apps(workspace_id, trash_can, conn)?;
send_dart_notification(workspace_id, WorkspaceNotification::WorkspaceAppsChanged)
.payload(repeated_app)
.send();
Ok(())
}
fn read_local_workspace_apps(
workspace_id: &str,
trash_can: Arc<TrashCan>,
conn: &SqliteConnection,
) -> Result<RepeatedApp, WorkspaceError> {
let mut app_tables = AppTableSql::read_workspace_apps(workspace_id, false, conn)?;
let trash_ids = trash_can.trash_ids(conn)?;
app_tables.retain(|app_table| !trash_ids.contains(&app_table.id));
let apps = app_tables.into_iter().map(|table| table.into()).collect::<Vec<App>>();
Ok(RepeatedApp { items: apps })
}
// #[tracing::instrument(level = "debug", skip(self), err)]
// pub(crate) async fn delete_app(&self, app_id: &str) -> Result<(),
// WorkspaceError> { let conn = &*self.database.db_connection()?;
// conn.immediate_transaction::<_, WorkspaceError, _>(|| {
// let app = AppTableSql::delete_app(app_id, &*conn)?;
// let apps = self.read_local_apps(&app.workspace_id, &*conn)?;
// send_dart_notification(&app.workspace_id,
// WorkspaceNotification::WorkspaceDeleteApp) .payload(apps)
// .send();
// Ok(())
// })?;
//
// let _ = self.delete_app_on_server(app_id);
// Ok(())
// }
//
// #[tracing::instrument(level = "debug", skip(self), err)]
// fn delete_app_on_server(&self, app_id: &str) -> Result<(), WorkspaceError> {
// let token = self.user.token()?;
// let server = self.server.clone();
// let params = DeleteAppParams {
// app_id: app_id.to_string(),
// };
// spawn(async move {
// match server.delete_app(&token, params).await {
// Ok(_) => {},
// Err(e) => {
// // TODO: retry?
// log::error!("Delete app failed: {:?}", e);
// },
// }
// });
// // let action = RetryAction::new(self.server.clone(), self.user.clone(),
// move // |token, server| { let params = params.clone();
// // async move {
// // match server.delete_app(&token, params).await {
// // Ok(_) => {},
// // Err(e) => log::error!("Delete app failed: {:?}", e),
// // }
// // Ok::<(), WorkspaceError>(())
// // }
// // });
// //
// // spawn_retry(500, 3, action);
// Ok(())
// }

View File

@ -8,7 +8,7 @@ pub use server_api_mock::*;
use crate::{ use crate::{
entities::{ entities::{
app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, UpdateAppParams}, app::{App, AppIdentifier, CreateAppParams, UpdateAppParams},
trash::{RepeatedTrash, TrashIdentifiers}, trash::{RepeatedTrash, TrashIdentifiers},
view::{CreateViewParams, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers}, view::{CreateViewParams, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers},
workspace::{ workspace::{
@ -58,7 +58,7 @@ pub trait WorkspaceServerAPI {
fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>; fn update_app(&self, token: &str, params: UpdateAppParams) -> ResultFuture<(), WorkspaceError>;
fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError>; fn delete_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<(), WorkspaceError>;
// Trash // Trash
fn create_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError>; fn create_trash(&self, token: &str, params: TrashIdentifiers) -> ResultFuture<(), WorkspaceError>;

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
entities::{ entities::{
app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, UpdateAppParams}, app::{App, AppIdentifier, CreateAppParams, UpdateAppParams},
trash::{RepeatedTrash, TrashIdentifiers}, trash::{RepeatedTrash, TrashIdentifiers},
view::{CreateViewParams, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers}, view::{CreateViewParams, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers},
workspace::{ workspace::{
@ -97,7 +97,7 @@ impl WorkspaceServerAPI for WorkspaceServer {
ResultFuture::new(async move { update_app_request(&token, params, &url).await }) ResultFuture::new(async move { update_app_request(&token, params, &url).await })
} }
fn delete_app(&self, token: &str, params: DeleteAppParams) -> ResultFuture<(), WorkspaceError> { fn delete_app(&self, token: &str, params: AppIdentifier) -> ResultFuture<(), WorkspaceError> {
let token = token.to_owned(); let token = token.to_owned();
let url = self.config.app_url(); let url = self.config.app_url();
ResultFuture::new(async move { delete_app_request(&token, params, &url).await }) ResultFuture::new(async move { delete_app_request(&token, params, &url).await })
@ -214,7 +214,7 @@ pub async fn update_app_request(token: &str, params: UpdateAppParams, url: &str)
Ok(()) Ok(())
} }
pub async fn delete_app_request(token: &str, params: DeleteAppParams, url: &str) -> Result<(), WorkspaceError> { pub async fn delete_app_request(token: &str, params: AppIdentifier, url: &str) -> Result<(), WorkspaceError> {
let _ = request_builder() let _ = request_builder()
.delete(&url.to_owned()) .delete(&url.to_owned())
.header(HEADER_TOKEN, token) .header(HEADER_TOKEN, token)

View File

@ -1,6 +1,6 @@
use crate::{ use crate::{
entities::{ entities::{
app::{App, AppIdentifier, CreateAppParams, DeleteAppParams, RepeatedApp, UpdateAppParams}, app::{App, AppIdentifier, CreateAppParams, RepeatedApp, UpdateAppParams},
trash::{RepeatedTrash, TrashIdentifiers}, trash::{RepeatedTrash, TrashIdentifiers},
view::{CreateViewParams, RepeatedView, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers}, view::{CreateViewParams, RepeatedView, UpdateViewParams, View, ViewIdentifier, ViewIdentifiers},
workspace::{ workspace::{
@ -104,7 +104,7 @@ impl WorkspaceServerAPI for WorkspaceServerMock {
ResultFuture::new(async { Ok(()) }) ResultFuture::new(async { Ok(()) })
} }
fn delete_app(&self, _token: &str, _params: DeleteAppParams) -> ResultFuture<(), WorkspaceError> { fn delete_app(&self, _token: &str, _params: AppIdentifier) -> ResultFuture<(), WorkspaceError> {
ResultFuture::new(async { Ok(()) }) ResultFuture::new(async { Ok(()) })
} }

View File

@ -64,10 +64,8 @@ impl ViewController {
conn.immediate_transaction::<_, WorkspaceError, _>(|| { conn.immediate_transaction::<_, WorkspaceError, _>(|| {
let _ = self.save_view(view.clone(), conn)?; let _ = self.save_view(view.clone(), conn)?;
let repeated_view = read_belonging_view(&view.belong_to_id, trash_can, &conn)?; let _ = notify_view_num_changed(&view.belong_to_id, trash_can, &conn)?;
send_dart_notification(&view.belong_to_id, WorkspaceNotification::AppViewsChanged)
.payload(repeated_view)
.send();
Ok(()) Ok(())
})?; })?;
@ -145,7 +143,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 = read_belonging_view(belong_to_id, self.trash_can.clone(), &conn)?; let repeated_view = read_local_belonging_view(belong_to_id, self.trash_can.clone(), &conn)?;
Ok(repeated_view) Ok(repeated_view)
} }
@ -309,7 +307,7 @@ fn notify_view_num_changed(
trash_can: Arc<TrashCan>, trash_can: Arc<TrashCan>,
conn: &SqliteConnection, conn: &SqliteConnection,
) -> WorkspaceResult<()> { ) -> WorkspaceResult<()> {
let repeated_view = read_belonging_view(belong_to_id, trash_can.clone(), conn)?; let repeated_view = read_local_belonging_view(belong_to_id, trash_can.clone(), conn)?;
tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str()); tracing::Span::current().record("view_count", &format!("{}", repeated_view.len()).as_str());
send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged) send_dart_notification(&belong_to_id, WorkspaceNotification::AppViewsChanged)
.payload(repeated_view) .payload(repeated_view)
@ -317,13 +315,19 @@ fn notify_view_num_changed(
Ok(()) Ok(())
} }
fn read_belonging_view( fn read_local_belonging_view(
belong_to_id: &str, belong_to_id: &str,
trash_can: Arc<TrashCan>, trash_can: Arc<TrashCan>,
conn: &SqliteConnection, conn: &SqliteConnection,
) -> WorkspaceResult<RepeatedView> { ) -> WorkspaceResult<RepeatedView> {
let mut repeated_view = ViewTableSql::read_views(belong_to_id, conn)?; let mut view_tables = ViewTableSql::read_views(belong_to_id, conn)?;
let trash_ids = trash_can.trash_ids(conn)?; let trash_ids = trash_can.trash_ids(conn)?;
repeated_view.retain(|view| !trash_ids.contains(&view.id)); view_tables.retain(|view_table| !trash_ids.contains(&view_table.id));
Ok(repeated_view)
let views = view_tables
.into_iter()
.map(|view_table| view_table.into())
.collect::<Vec<View>>();
Ok(RepeatedView { items: views })
} }

View File

@ -47,6 +47,7 @@ impl WorkspaceController {
pub fn init(&self) -> Result<(), WorkspaceError> { pub fn init(&self) -> Result<(), WorkspaceError> {
let _ = self.trash_can.init()?; let _ = self.trash_can.init()?;
let _ = self.view_controller.init()?; let _ = self.view_controller.init()?;
let _ = self.app_controller.init()?;
Ok(()) Ok(())
} }

View File

@ -29,16 +29,11 @@ impl AppTableSql {
pub(crate) fn read_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> { pub(crate) fn read_app(app_id: &str, conn: &SqliteConnection) -> Result<AppTable, WorkspaceError> {
let filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed(); let filter = dsl::app_table.filter(app_table::id.eq(app_id)).into_boxed();
// if let Some(is_trash) = is_trash {
// filter = filter.filter(app_table::is_trash.eq(is_trash));
// }
let app_table = filter.first::<AppTable>(conn)?; let app_table = filter.first::<AppTable>(conn)?;
Ok(app_table) Ok(app_table)
} }
pub(crate) fn read_apps( pub(crate) fn read_workspace_apps(
workspace_id: &str, workspace_id: &str,
is_trash: bool, is_trash: bool,
conn: &SqliteConnection, conn: &SqliteConnection,

View File

@ -8,6 +8,7 @@ use crate::{
use diesel::sql_types::Binary; use diesel::sql_types::Binary;
use flowy_database::schema::app_table; use flowy_database::schema::app_table;
use crate::entities::trash::{Trash, TrashType};
use serde::{Deserialize, Serialize, __private::TryFrom}; use serde::{Deserialize, Serialize, __private::TryFrom};
use std::convert::TryInto; use std::convert::TryInto;
@ -44,6 +45,18 @@ impl AppTable {
} }
} }
impl std::convert::Into<Trash> for AppTable {
fn into(self) -> Trash {
Trash {
id: self.id,
name: self.name,
modified_time: self.modified_time,
create_time: self.create_time,
ty: TrashType::App,
}
}
}
#[derive(Clone, PartialEq, Serialize, Deserialize, Debug, Default, FromSqlRow, AsExpression)] #[derive(Clone, PartialEq, Serialize, Deserialize, Debug, Default, FromSqlRow, AsExpression)]
#[sql_type = "Binary"] #[sql_type = "Binary"]
pub(crate) struct ColorStyleCol { pub(crate) struct ColorStyleCol {

View File

@ -61,6 +61,7 @@ impl std::convert::From<TrashTable> for TrashTableChangeset {
pub(crate) enum SqlTrashType { pub(crate) enum SqlTrashType {
Unknown = 0, Unknown = 0,
View = 1, View = 1,
App = 2,
} }
impl std::convert::From<i32> for SqlTrashType { impl std::convert::From<i32> for SqlTrashType {
@ -68,6 +69,7 @@ impl std::convert::From<i32> for SqlTrashType {
match value { match value {
0 => SqlTrashType::Unknown, 0 => SqlTrashType::Unknown,
1 => SqlTrashType::View, 1 => SqlTrashType::View,
2 => SqlTrashType::App,
_o => SqlTrashType::Unknown, _o => SqlTrashType::Unknown,
} }
} }
@ -80,6 +82,7 @@ impl std::convert::Into<TrashType> for SqlTrashType {
match self { match self {
SqlTrashType::Unknown => TrashType::Unknown, SqlTrashType::Unknown => TrashType::Unknown,
SqlTrashType::View => TrashType::View, SqlTrashType::View => TrashType::View,
SqlTrashType::App => TrashType::App,
} }
} }
} }
@ -89,6 +92,7 @@ impl std::convert::From<TrashType> for SqlTrashType {
match ty { match ty {
TrashType::Unknown => SqlTrashType::Unknown, TrashType::Unknown => SqlTrashType::Unknown,
TrashType::View => SqlTrashType::View, TrashType::View => SqlTrashType::View,
TrashType::App => SqlTrashType::App,
} }
} }
} }

View File

@ -1,5 +1,4 @@
use crate::{ use crate::{
entities::view::{RepeatedView, View},
errors::WorkspaceError, errors::WorkspaceError,
sql_tables::view::{ViewTable, ViewTableChangeset}, sql_tables::view::{ViewTable, ViewTableChangeset},
}; };
@ -39,18 +38,13 @@ impl ViewTableSql {
} }
// 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<Vec<ViewTable>, WorkspaceError> {
let 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 views = view_tables Ok(view_tables)
.into_iter()
.map(|view_table| view_table.into())
.collect::<Vec<View>>();
Ok(RepeatedView { items: views })
} }
pub(crate) fn update_view(changeset: ViewTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> { pub(crate) fn update_view(changeset: ViewTableChangeset, conn: &SqliteConnection) -> Result<(), WorkspaceError> {

View File

@ -6,14 +6,18 @@ use flowy_workspace::entities::{app::QueryAppRequest, view::*};
async fn app_delete() { async fn app_delete() {
let test = AppTest::new().await; let test = AppTest::new().await;
delete_app(&test.sdk, &test.app.id).await; delete_app(&test.sdk, &test.app.id).await;
let query = QueryAppRequest::new(&test.app.id); let query = QueryAppRequest {
app_ids: vec![test.app.id.clone()],
};
let _ = read_app(&test.sdk, query).await; let _ = read_app(&test.sdk, query).await;
} }
#[tokio::test] #[tokio::test]
async fn app_read() { async fn app_read() {
let test = AppTest::new().await; let test = AppTest::new().await;
let query = QueryAppRequest::new(&test.app.id); let query = QueryAppRequest {
app_ids: vec![test.app.id.clone()],
};
let app_from_db = read_app(&test.sdk, query).await; let app_from_db = read_app(&test.sdk, query).await;
assert_eq!(app_from_db, test.app); assert_eq!(app_from_db, test.app);
} }
@ -40,7 +44,9 @@ async fn app_create_with_view() {
let view_a = create_view_with_request(&test.sdk, request_a).await; let view_a = create_view_with_request(&test.sdk, request_a).await;
let view_b = create_view_with_request(&test.sdk, request_b).await; let view_b = create_view_with_request(&test.sdk, request_b).await;
let query = QueryAppRequest::new(&test.app.id); let query = QueryAppRequest {
app_ids: vec![test.app.id.clone()],
};
let view_from_db = read_app(&test.sdk, query).await; let view_from_db = read_app(&test.sdk, query).await;
assert_eq!(view_from_db.belongings[0], view_a); assert_eq!(view_from_db.belongings[0], view_a);

View File

@ -9,7 +9,7 @@ use flowy_workspace::entities::{
#[should_panic] #[should_panic]
async fn view_delete() { async fn view_delete() {
let test = FlowyTest::setup(); let test = FlowyTest::setup();
let _ = test.init_user(); let _ = test.init_user().await;
let test = ViewTest::new(&test).await; let test = ViewTest::new(&test).await;
test.delete_views(vec![test.view.id.clone()]).await; test.delete_views(vec![test.view.id.clone()]).await;
@ -22,7 +22,7 @@ async fn view_delete() {
#[tokio::test] #[tokio::test]
async fn view_delete_then_putback() { async fn view_delete_then_putback() {
let test = FlowyTest::setup(); let test = FlowyTest::setup();
let _ = test.init_user(); let _ = test.init_user().await;
let test = ViewTest::new(&test).await; let test = ViewTest::new(&test).await;
test.delete_views(vec![test.view.id.clone()]).await; test.delete_views(vec![test.view.id.clone()]).await;
@ -45,7 +45,7 @@ async fn view_delete_then_putback() {
#[tokio::test] #[tokio::test]
async fn view_delete_all() { async fn view_delete_all() {
let test = FlowyTest::setup(); let test = FlowyTest::setup();
let _ = test.init_user(); let _ = test.init_user().await;
let test = ViewTest::new(&test).await; let test = ViewTest::new(&test).await;
let view1 = test.view.clone(); let view1 = test.view.clone();
@ -53,7 +53,9 @@ async fn view_delete_all() {
let view3 = create_view(&test.sdk, &test.app.id).await; let view3 = create_view(&test.sdk, &test.app.id).await;
let view_ids = vec![view1.id.clone(), view2.id.clone(), view3.id.clone()]; let view_ids = vec![view1.id.clone(), view2.id.clone(), view3.id.clone()];
let query = QueryAppRequest::new(&test.app.id); let query = QueryAppRequest {
app_ids: vec![test.app.id.clone()],
};
let app = read_app(&test.sdk, query.clone()).await; let app = read_app(&test.sdk, query.clone()).await;
assert_eq!(app.belongings.len(), view_ids.len()); assert_eq!(app.belongings.len(), view_ids.len());
test.delete_views(view_ids.clone()).await; test.delete_views(view_ids.clone()).await;
@ -65,7 +67,7 @@ async fn view_delete_all() {
#[tokio::test] #[tokio::test]
async fn view_delete_all_permanent() { async fn view_delete_all_permanent() {
let test = FlowyTest::setup(); let test = FlowyTest::setup();
let _ = test.init_user(); let _ = test.init_user().await;
let test = ViewTest::new(&test).await; let test = ViewTest::new(&test).await;
let view1 = test.view.clone(); let view1 = test.view.clone();
@ -74,7 +76,9 @@ async fn view_delete_all_permanent() {
let view_ids = vec![view1.id.clone(), view2.id.clone()]; let view_ids = vec![view1.id.clone(), view2.id.clone()];
test.delete_views_permanent(view_ids).await; test.delete_views_permanent(view_ids).await;
let query = QueryAppRequest::new(&test.app.id); let query = QueryAppRequest {
app_ids: vec![test.app.id.clone()],
};
assert_eq!(read_app(&test.sdk, query).await.belongings.len(), 0); assert_eq!(read_app(&test.sdk, query).await.belongings.len(), 0);
assert_eq!(read_trash(&test.sdk).await.len(), 0); assert_eq!(read_trash(&test.sdk).await.len(), 0);
} }