chore: save view order

This commit is contained in:
appflowy 2022-04-26 21:20:02 +08:00
parent 25548ad9eb
commit 7f7801d04e
22 changed files with 687 additions and 32 deletions

View File

@ -1,16 +1,23 @@
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:app_flowy/plugin/plugin.dart';
class AppService {
Future<Either<App, FlowyError>> getAppDesc({required String appId}) {
final request = AppId.create()..value = appId;
final String appId;
AppService({
required this.appId,
});
return FolderEventReadApp(request).send();
Future<Either<App, FlowyError>> getAppDesc({required String appId}) {
final payload = AppId.create()..value = appId;
return FolderEventReadApp(payload).send();
}
Future<Either<View, FlowyError>> createView({
@ -20,20 +27,20 @@ class AppService {
required PluginDataType dataType,
required PluginType pluginType,
}) {
final request = CreateViewPayload.create()
final payload = CreateViewPayload.create()
..belongToId = appId
..name = name
..desc = desc
..dataType = dataType
..pluginType = pluginType;
return FolderEventCreateView(request).send();
return FolderEventCreateView(payload).send();
}
Future<Either<List<View>, FlowyError>> getViews({required String appId}) {
final request = AppId.create()..value = appId;
final payload = AppId.create()..value = appId;
return FolderEventReadApp(request).send().then((result) {
return FolderEventReadApp(payload).send().then((result) {
return result.fold(
(app) => left(app.belongings.items),
(error) => right(error),
@ -47,12 +54,12 @@ class AppService {
}
Future<Either<Unit, FlowyError>> updateApp({required String appId, String? name}) {
UpdateAppPayload request = UpdateAppPayload.create()..appId = appId;
UpdateAppPayload payload = UpdateAppPayload.create()..appId = appId;
if (name != null) {
request.name = name;
payload.name = name;
}
return FolderEventUpdateApp(request).send();
return FolderEventUpdateApp(payload).send();
}
Future<Either<Unit, FlowyError>> moveView({
@ -60,11 +67,12 @@ class AppService {
required int fromIndex,
required int toIndex,
}) {
UpdateAppPayload request = UpdateAppPayload.create()..appId = appId;
final payload = MoveFolderItemPayload.create()
..itemId = viewId
..from = fromIndex
..to = toIndex
..ty = MoveFolderItemType.MoveView;
if (name != null) {
request.name = name;
}
return FolderEventUpdateApp(request).send();
return FolderEventMoveItem(payload).send();
}
}

View File

@ -3,22 +3,23 @@ import 'package:dartz/dartz.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_sdk/dispatch/dispatch.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/app.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/view.pb.dart' show MoveFolderItemPayload, MoveItemType;
import 'package:flowy_sdk/protobuf/flowy-folder-data-model/workspace.pb.dart';
import 'package:flowy_sdk/protobuf/flowy-error/errors.pb.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
class WorkspaceService {
Future<Either<App, FlowyError>> createApp({required String workspaceId, required String name, required String desc}) {
final request = CreateAppPayload.create()
final payload = CreateAppPayload.create()
..name = name
..workspaceId = workspaceId
..desc = desc;
return FolderEventCreateApp(request).send();
return FolderEventCreateApp(payload).send();
}
Future<Either<Workspace, FlowyError>> getWorkspace({required String workspaceId}) {
final request = WorkspaceId.create()..value = workspaceId;
return FolderEventReadWorkspaces(request).send().then((result) {
final payload = WorkspaceId.create()..value = workspaceId;
return FolderEventReadWorkspaces(payload).send().then((result) {
return result.fold(
(workspaces) {
assert(workspaces.items.length == 1);
@ -35,12 +36,26 @@ class WorkspaceService {
}
Future<Either<List<App>, FlowyError>> getApps({required String workspaceId}) {
final request = WorkspaceId.create()..value = workspaceId;
return FolderEventReadWorkspaceApps(request).send().then((result) {
final payload = WorkspaceId.create()..value = workspaceId;
return FolderEventReadWorkspaceApps(payload).send().then((result) {
return result.fold(
(apps) => left(apps.items),
(error) => right(error),
);
});
}
Future<Either<Unit, FlowyError>> moveApp({
required String appId,
required int fromIndex,
required int toIndex,
}) {
final payload = MoveFolderItemPayload.create()
..itemId = appId
..from = fromIndex
..to = toIndex
..ty = MoveItemType.MoveApp;
return FolderEventMoveItem(payload).send();
}
}

View File

@ -4,7 +4,6 @@ import 'package:app_flowy/workspace/application/menu/menu_view_section_bloc.dart
import 'package:app_flowy/workspace/application/view/view_ext.dart';
import 'package:app_flowy/workspace/presentation/home/home_stack.dart';
import 'package:app_flowy/workspace/presentation/home/menu/menu.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:reorderables/reorderables.dart';

View File

@ -301,6 +301,23 @@ class FolderEventCloseView {
}
}
class FolderEventMoveItem {
MoveFolderItemPayload request;
FolderEventMoveItem(this.request);
Future<Either<Unit, FlowyError>> send() {
final request = FFIRequest.create()
..event = FolderEvent.MoveItem.toString()
..payload = requestToBytes(this.request);
return Dispatch.asyncRequest(request)
.then((bytesResult) => bytesResult.fold(
(bytes) => left(unit),
(errBytes) => right(FlowyError.fromBuffer(errBytes)),
));
}
}
class FolderEventReadTrash {
FolderEventReadTrash();

View File

@ -891,3 +891,92 @@ class UpdateViewParams extends $pb.GeneratedMessage {
void clearThumbnail() => clearField(4);
}
class MoveFolderItemPayload extends $pb.GeneratedMessage {
static final $pb.BuilderInfo _i = $pb.BuilderInfo(const $core.bool.fromEnvironment('protobuf.omit_message_names') ? '' : 'MoveFolderItemPayload', createEmptyInstance: create)
..aOS(1, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'itemId')
..a<$core.int>(2, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'from', $pb.PbFieldType.O3)
..a<$core.int>(3, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'to', $pb.PbFieldType.O3)
..e<MoveFolderItemType>(4, const $core.bool.fromEnvironment('protobuf.omit_field_names') ? '' : 'ty', $pb.PbFieldType.OE, defaultOrMaker: MoveFolderItemType.MoveApp, valueOf: MoveFolderItemType.valueOf, enumValues: MoveFolderItemType.values)
..hasRequiredFields = false
;
MoveFolderItemPayload._() : super();
factory MoveFolderItemPayload({
$core.String? itemId,
$core.int? from,
$core.int? to,
MoveFolderItemType? ty,
}) {
final _result = create();
if (itemId != null) {
_result.itemId = itemId;
}
if (from != null) {
_result.from = from;
}
if (to != null) {
_result.to = to;
}
if (ty != null) {
_result.ty = ty;
}
return _result;
}
factory MoveFolderItemPayload.fromBuffer($core.List<$core.int> i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromBuffer(i, r);
factory MoveFolderItemPayload.fromJson($core.String i, [$pb.ExtensionRegistry r = $pb.ExtensionRegistry.EMPTY]) => create()..mergeFromJson(i, r);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.deepCopy] instead. '
'Will be removed in next major version')
MoveFolderItemPayload clone() => MoveFolderItemPayload()..mergeFromMessage(this);
@$core.Deprecated(
'Using this can add significant overhead to your binary. '
'Use [GeneratedMessageGenericExtensions.rebuild] instead. '
'Will be removed in next major version')
MoveFolderItemPayload copyWith(void Function(MoveFolderItemPayload) updates) => super.copyWith((message) => updates(message as MoveFolderItemPayload)) as MoveFolderItemPayload; // ignore: deprecated_member_use
$pb.BuilderInfo get info_ => _i;
@$core.pragma('dart2js:noInline')
static MoveFolderItemPayload create() => MoveFolderItemPayload._();
MoveFolderItemPayload createEmptyInstance() => create();
static $pb.PbList<MoveFolderItemPayload> createRepeated() => $pb.PbList<MoveFolderItemPayload>();
@$core.pragma('dart2js:noInline')
static MoveFolderItemPayload getDefault() => _defaultInstance ??= $pb.GeneratedMessage.$_defaultFor<MoveFolderItemPayload>(create);
static MoveFolderItemPayload? _defaultInstance;
@$pb.TagNumber(1)
$core.String get itemId => $_getSZ(0);
@$pb.TagNumber(1)
set itemId($core.String v) { $_setString(0, v); }
@$pb.TagNumber(1)
$core.bool hasItemId() => $_has(0);
@$pb.TagNumber(1)
void clearItemId() => clearField(1);
@$pb.TagNumber(2)
$core.int get from => $_getIZ(1);
@$pb.TagNumber(2)
set from($core.int v) { $_setSignedInt32(1, v); }
@$pb.TagNumber(2)
$core.bool hasFrom() => $_has(1);
@$pb.TagNumber(2)
void clearFrom() => clearField(2);
@$pb.TagNumber(3)
$core.int get to => $_getIZ(2);
@$pb.TagNumber(3)
set to($core.int v) { $_setSignedInt32(2, v); }
@$pb.TagNumber(3)
$core.bool hasTo() => $_has(2);
@$pb.TagNumber(3)
void clearTo() => clearField(3);
@$pb.TagNumber(4)
MoveFolderItemType get ty => $_getN(3);
@$pb.TagNumber(4)
set ty(MoveFolderItemType v) { setField(4, v); }
@$pb.TagNumber(4)
$core.bool hasTy() => $_has(3);
@$pb.TagNumber(4)
void clearTy() => clearField(4);
}

View File

@ -24,3 +24,18 @@ class ViewDataType extends $pb.ProtobufEnum {
const ViewDataType._($core.int v, $core.String n) : super(v, n);
}
class MoveFolderItemType extends $pb.ProtobufEnum {
static const MoveFolderItemType MoveApp = MoveFolderItemType._(0, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveApp');
static const MoveFolderItemType MoveView = MoveFolderItemType._(1, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveView');
static const $core.List<MoveFolderItemType> values = <MoveFolderItemType> [
MoveApp,
MoveView,
];
static final $core.Map<$core.int, MoveFolderItemType> _byValue = $pb.ProtobufEnum.initByValue(values);
static MoveFolderItemType? valueOf($core.int value) => _byValue[value];
const MoveFolderItemType._($core.int v, $core.String n) : super(v, n);
}

View File

@ -19,6 +19,17 @@ const ViewDataType$json = const {
/// Descriptor for `ViewDataType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List viewDataTypeDescriptor = $convert.base64Decode('CgxWaWV3RGF0YVR5cGUSDQoJVGV4dEJsb2NrEAASCAoER3JpZBAB');
@$core.Deprecated('Use moveFolderItemTypeDescriptor instead')
const MoveFolderItemType$json = const {
'1': 'MoveFolderItemType',
'2': const [
const {'1': 'MoveApp', '2': 0},
const {'1': 'MoveView', '2': 1},
],
};
/// Descriptor for `MoveFolderItemType`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List moveFolderItemTypeDescriptor = $convert.base64Decode('ChJNb3ZlRm9sZGVySXRlbVR5cGUSCwoHTW92ZUFwcBAAEgwKCE1vdmVWaWV3EAE=');
@$core.Deprecated('Use viewDescriptor instead')
const View$json = const {
'1': 'View',
@ -142,3 +153,16 @@ const UpdateViewParams$json = const {
/// Descriptor for `UpdateViewParams`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List updateViewParamsDescriptor = $convert.base64Decode('ChBVcGRhdGVWaWV3UGFyYW1zEhcKB3ZpZXdfaWQYASABKAlSBnZpZXdJZBIUCgRuYW1lGAIgASgJSABSBG5hbWUSFAoEZGVzYxgDIAEoCUgBUgRkZXNjEh4KCXRodW1ibmFpbBgEIAEoCUgCUgl0aHVtYm5haWxCDQoLb25lX29mX25hbWVCDQoLb25lX29mX2Rlc2NCEgoQb25lX29mX3RodW1ibmFpbA==');
@$core.Deprecated('Use moveFolderItemPayloadDescriptor instead')
const MoveFolderItemPayload$json = const {
'1': 'MoveFolderItemPayload',
'2': const [
const {'1': 'item_id', '3': 1, '4': 1, '5': 9, '10': 'itemId'},
const {'1': 'from', '3': 2, '4': 1, '5': 5, '10': 'from'},
const {'1': 'to', '3': 3, '4': 1, '5': 5, '10': 'to'},
const {'1': 'ty', '3': 4, '4': 1, '5': 14, '6': '.MoveFolderItemType', '10': 'ty'},
],
};
/// Descriptor for `MoveFolderItemPayload`. Decode as a `google.protobuf.DescriptorProto`.
final $typed_data.Uint8List moveFolderItemPayloadDescriptor = $convert.base64Decode('ChVNb3ZlRm9sZGVySXRlbVBheWxvYWQSFwoHaXRlbV9pZBgBIAEoCVIGaXRlbUlkEhIKBGZyb20YAiABKAVSBGZyb20SDgoCdG8YAyABKAVSAnRvEiMKAnR5GAQgASgOMhMuTW92ZUZvbGRlckl0ZW1UeXBlUgJ0eQ==');

View File

@ -28,6 +28,7 @@ class FolderEvent extends $pb.ProtobufEnum {
static const FolderEvent CopyLink = FolderEvent._(206, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CopyLink');
static const FolderEvent SetLatestView = FolderEvent._(207, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'SetLatestView');
static const FolderEvent CloseView = FolderEvent._(208, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'CloseView');
static const FolderEvent MoveItem = FolderEvent._(209, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'MoveItem');
static const FolderEvent ReadTrash = FolderEvent._(300, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'ReadTrash');
static const FolderEvent PutbackTrash = FolderEvent._(301, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'PutbackTrash');
static const FolderEvent DeleteTrash = FolderEvent._(302, const $core.bool.fromEnvironment('protobuf.omit_enum_names') ? '' : 'DeleteTrash');
@ -53,6 +54,7 @@ class FolderEvent extends $pb.ProtobufEnum {
CopyLink,
SetLatestView,
CloseView,
MoveItem,
ReadTrash,
PutbackTrash,
DeleteTrash,

View File

@ -30,6 +30,7 @@ const FolderEvent$json = const {
const {'1': 'CopyLink', '2': 206},
const {'1': 'SetLatestView', '2': 207},
const {'1': 'CloseView', '2': 208},
const {'1': 'MoveItem', '2': 209},
const {'1': 'ReadTrash', '2': 300},
const {'1': 'PutbackTrash', '2': 301},
const {'1': 'DeleteTrash', '2': 302},
@ -39,4 +40,4 @@ const FolderEvent$json = const {
};
/// Descriptor for `FolderEvent`. Decode as a `google.protobuf.EnumDescriptorProto`.
final $typed_data.Uint8List folderEventDescriptor = $convert.base64Decode('CgtGb2xkZXJFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARISCg1TZXRMYXRlc3RWaWV3EM8BEg4KCUNsb3NlVmlldxDQARIOCglSZWFkVHJhc2gQrAISEQoMUHV0YmFja1RyYXNoEK0CEhAKC0RlbGV0ZVRyYXNoEK4CEhQKD1Jlc3RvcmVBbGxUcmFzaBCvAhITCg5EZWxldGVBbGxUcmFzaBCwAg==');
final $typed_data.Uint8List folderEventDescriptor = $convert.base64Decode('CgtGb2xkZXJFdmVudBITCg9DcmVhdGVXb3Jrc3BhY2UQABIUChBSZWFkQ3VyV29ya3NwYWNlEAESEgoOUmVhZFdvcmtzcGFjZXMQAhITCg9EZWxldGVXb3Jrc3BhY2UQAxIRCg1PcGVuV29ya3NwYWNlEAQSFQoRUmVhZFdvcmtzcGFjZUFwcHMQBRINCglDcmVhdGVBcHAQZRINCglEZWxldGVBcHAQZhILCgdSZWFkQXBwEGcSDQoJVXBkYXRlQXBwEGgSDwoKQ3JlYXRlVmlldxDJARINCghSZWFkVmlldxDKARIPCgpVcGRhdGVWaWV3EMsBEg8KCkRlbGV0ZVZpZXcQzAESEgoNRHVwbGljYXRlVmlldxDNARINCghDb3B5TGluaxDOARISCg1TZXRMYXRlc3RWaWV3EM8BEg4KCUNsb3NlVmlldxDQARINCghNb3ZlSXRlbRDRARIOCglSZWFkVHJhc2gQrAISEQoMUHV0YmFja1RyYXNoEK0CEhAKC0RlbGV0ZVRyYXNoEK4CEhQKD1Jlc3RvcmVBbGxUcmFzaBCvAhITCg5EZWxldGVBbGxUcmFzaBCwAg==');

View File

@ -62,7 +62,8 @@ pub fn create(folder: Arc<FolderManager>) -> Module {
.event(FolderEvent::DeleteView, delete_view_handler)
.event(FolderEvent::DuplicateView, duplicate_view_handler)
.event(FolderEvent::SetLatestView, set_latest_view_handler)
.event(FolderEvent::CloseView, close_view_handler);
.event(FolderEvent::CloseView, close_view_handler)
.event(FolderEvent::MoveItem, move_item_handler);
module = module
.event(FolderEvent::ReadTrash, read_trash_handler)
@ -131,6 +132,9 @@ pub enum FolderEvent {
#[event(input = "ViewId")]
CloseView = 208,
#[event(input = "MoveFolderItemPayload")]
MoveItem = 209,
#[event(output = "RepeatedTrash")]
ReadTrash = 300,

View File

@ -43,6 +43,7 @@ pub enum FolderEvent {
CopyLink = 206,
SetLatestView = 207,
CloseView = 208,
MoveItem = 209,
ReadTrash = 300,
PutbackTrash = 301,
DeleteTrash = 302,
@ -75,6 +76,7 @@ impl ::protobuf::ProtobufEnum for FolderEvent {
206 => ::std::option::Option::Some(FolderEvent::CopyLink),
207 => ::std::option::Option::Some(FolderEvent::SetLatestView),
208 => ::std::option::Option::Some(FolderEvent::CloseView),
209 => ::std::option::Option::Some(FolderEvent::MoveItem),
300 => ::std::option::Option::Some(FolderEvent::ReadTrash),
301 => ::std::option::Option::Some(FolderEvent::PutbackTrash),
302 => ::std::option::Option::Some(FolderEvent::DeleteTrash),
@ -104,6 +106,7 @@ impl ::protobuf::ProtobufEnum for FolderEvent {
FolderEvent::CopyLink,
FolderEvent::SetLatestView,
FolderEvent::CloseView,
FolderEvent::MoveItem,
FolderEvent::ReadTrash,
FolderEvent::PutbackTrash,
FolderEvent::DeleteTrash,
@ -137,7 +140,7 @@ impl ::protobuf::reflect::ProtobufValue for FolderEvent {
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\x0fevent_map.proto*\xae\x03\n\x0bFolderEvent\x12\x13\n\x0fCreateWorks\
\n\x0fevent_map.proto*\xbd\x03\n\x0bFolderEvent\x12\x13\n\x0fCreateWorks\
pace\x10\0\x12\x14\n\x10ReadCurWorkspace\x10\x01\x12\x12\n\x0eReadWorksp\
aces\x10\x02\x12\x13\n\x0fDeleteWorkspace\x10\x03\x12\x11\n\rOpenWorkspa\
ce\x10\x04\x12\x15\n\x11ReadWorkspaceApps\x10\x05\x12\r\n\tCreateApp\x10\
@ -145,10 +148,11 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\x10h\x12\x0f\n\nCreateView\x10\xc9\x01\x12\r\n\x08ReadView\x10\xca\x01\
\x12\x0f\n\nUpdateView\x10\xcb\x01\x12\x0f\n\nDeleteView\x10\xcc\x01\x12\
\x12\n\rDuplicateView\x10\xcd\x01\x12\r\n\x08CopyLink\x10\xce\x01\x12\
\x12\n\rSetLatestView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\
\x0e\n\tReadTrash\x10\xac\x02\x12\x11\n\x0cPutbackTrash\x10\xad\x02\x12\
\x10\n\x0bDeleteTrash\x10\xae\x02\x12\x14\n\x0fRestoreAllTrash\x10\xaf\
\x02\x12\x13\n\x0eDeleteAllTrash\x10\xb0\x02b\x06proto3\
\x12\n\rSetLatestView\x10\xcf\x01\x12\x0e\n\tCloseView\x10\xd0\x01\x12\r\
\n\x08MoveItem\x10\xd1\x01\x12\x0e\n\tReadTrash\x10\xac\x02\x12\x11\n\
\x0cPutbackTrash\x10\xad\x02\x12\x10\n\x0bDeleteTrash\x10\xae\x02\x12\
\x14\n\x0fRestoreAllTrash\x10\xaf\x02\x12\x13\n\x0eDeleteAllTrash\x10\
\xb0\x02b\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -19,6 +19,7 @@ enum FolderEvent {
CopyLink = 206;
SetLatestView = 207;
CloseView = 208;
MoveItem = 209;
ReadTrash = 300;
PutbackTrash = 301;
DeleteTrash = 302;

View File

@ -95,6 +95,19 @@ impl AppController {
Ok(())
}
pub(crate) async fn move_app(&self, app_id: &str, from: usize, to: usize) -> FlowyResult<()> {
let _ = self
.persistence
.begin_transaction(|transaction| {
let _ = transaction.move_app(app_id, from, to)?;
let app = transaction.read_app(app_id)?;
let _ = notify_apps_changed(&app.workspace_id, self.trash_controller.clone(), &transaction)?;
Ok(())
})
.await?;
Ok(())
}
pub(crate) async fn read_local_apps(&self, ids: Vec<String>) -> Result<Vec<App>, FlowyError> {
let apps = self
.persistence

View File

@ -34,12 +34,14 @@ pub trait FolderPersistenceTransaction {
fn read_app(&self, app_id: &str) -> FlowyResult<App>;
fn read_workspace_apps(&self, workspace_id: &str) -> FlowyResult<Vec<App>>;
fn delete_app(&self, app_id: &str) -> FlowyResult<App>;
fn move_app(&self, app_id: &str, from: usize, to: usize) -> FlowyResult<()>;
fn create_view(&self, view: View) -> FlowyResult<()>;
fn read_view(&self, view_id: &str) -> FlowyResult<View>;
fn read_views(&self, belong_to_id: &str) -> FlowyResult<Vec<View>>;
fn update_view(&self, changeset: ViewChangeset) -> FlowyResult<()>;
fn delete_view(&self, view_id: &str) -> FlowyResult<()>;
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()>;
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()>;
fn read_trash(&self, trash_id: Option<String>) -> FlowyResult<RepeatedTrash>;

View File

@ -63,6 +63,10 @@ impl<'a> FolderPersistenceTransaction for V1Transaction<'a> {
Ok(App::from(table))
}
fn move_app(&self, _app_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
Ok(())
}
fn create_view(&self, view: View) -> FlowyResult<()> {
let _ = ViewTableSql::create_view(view, &*self.0)?;
Ok(())
@ -89,6 +93,10 @@ impl<'a> FolderPersistenceTransaction for V1Transaction<'a> {
Ok(())
}
fn move_view(&self, _view_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
Ok(())
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
let _ = TrashTableSql::create_trash(trashes, &*self.0)?;
Ok(())
@ -160,6 +168,10 @@ where
(**self).delete_app(app_id)
}
fn move_app(&self, _app_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
Ok(())
}
fn create_view(&self, view: View) -> FlowyResult<()> {
(**self).create_view(view)
}
@ -180,6 +192,10 @@ where
(**self).delete_view(view_id)
}
fn move_view(&self, _view_id: &str, _from: usize, _to: usize) -> FlowyResult<()> {
Ok(())
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
(**self).create_trash(trashes)
}

View File

@ -83,6 +83,13 @@ impl FolderPersistenceTransaction for ClientFolderEditor {
Ok(app)
}
fn move_app(&self, app_id: &str, from: usize, to: usize) -> FlowyResult<()> {
if let Some(change) = self.folder.write().move_app(app_id, from, to)? {
let _ = self.apply_change(change)?;
}
Ok(())
}
fn create_view(&self, view: View) -> FlowyResult<()> {
if let Some(change) = self.folder.write().create_view(view)? {
let _ = self.apply_change(change)?;
@ -118,6 +125,13 @@ impl FolderPersistenceTransaction for ClientFolderEditor {
Ok(())
}
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
if let Some(change) = self.folder.write().move_view(view_id, from, to)? {
let _ = self.apply_change(change)?;
}
Ok(())
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
if let Some(change) = self.folder.write().create_trash(trashes)? {
let _ = self.apply_change(change)?;
@ -178,6 +192,10 @@ where
(**self).delete_app(app_id)
}
fn move_app(&self, app_id: &str, from: usize, to: usize) -> FlowyResult<()> {
(**self).move_app(app_id, from, to)
}
fn create_view(&self, view: View) -> FlowyResult<()> {
(**self).create_view(view)
}
@ -198,6 +216,10 @@ where
(**self).delete_view(view_id)
}
fn move_view(&self, view_id: &str, from: usize, to: usize) -> FlowyResult<()> {
(**self).move_view(view_id, from, to)
}
fn create_trash(&self, trashes: Vec<Trash>) -> FlowyResult<()> {
(**self).create_trash(trashes)
}

View File

@ -154,6 +154,20 @@ impl ViewController {
Ok(())
}
#[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn move_view(&self, view_id: &str, from: usize, to: usize) -> Result<(), FlowyError> {
let _ = self
.persistence
.begin_transaction(|transaction| {
let _ = transaction.move_view(view_id, from, to)?;
let view = transaction.read_view(view_id)?;
let _ = notify_views_changed(&view.belong_to_id, self.trash_controller.clone(), &transaction)?;
Ok(())
})
.await?;
Ok(())
}
#[tracing::instrument(level = "debug", skip(self), err)]
pub(crate) async fn duplicate_view(&self, view_id: &str) -> Result<(), FlowyError> {
let view = self

View File

@ -1,3 +1,4 @@
use crate::services::AppController;
use crate::{
entities::{
trash::Trash,
@ -8,6 +9,7 @@ use crate::{
errors::FlowyError,
services::{TrashController, ViewController},
};
use flowy_folder_data_model::entities::view::{MoveFolderItemParams, MoveFolderItemPayload, MoveFolderItemType};
use lib_dispatch::prelude::{data_result, AppData, Data, DataResult};
use std::{convert::TryInto, sync::Arc};
@ -83,6 +85,26 @@ pub(crate) async fn close_view_handler(
Ok(())
}
#[tracing::instrument(level = "debug", skip_all, err)]
pub(crate) async fn move_item_handler(
data: Data<MoveFolderItemPayload>,
view_controller: AppData<Arc<ViewController>>,
app_controller: AppData<Arc<AppController>>,
) -> Result<(), FlowyError> {
let params: MoveFolderItemParams = data.into_inner().try_into()?;
match params.ty {
MoveFolderItemType::MoveApp => {
let _ = app_controller.move_app(&params.item_id, params.from, params.to).await?;
}
MoveFolderItemType::MoveView => {
let _ = view_controller
.move_view(&params.item_id, params.from, params.to)
.await?;
}
}
Ok(())
}
#[tracing::instrument(level = "debug", skip(data, controller), err)]
pub(crate) async fn duplicate_view_handler(
data: Data<ViewId>,

View File

@ -286,6 +286,54 @@ impl TryInto<UpdateViewParams> for UpdateViewPayload {
}
}
#[derive(ProtoBuf_Enum)]
pub enum MoveFolderItemType {
MoveApp = 0,
MoveView = 1,
}
impl std::default::Default for MoveFolderItemType {
fn default() -> Self {
MoveFolderItemType::MoveApp
}
}
#[derive(Default, ProtoBuf)]
pub struct MoveFolderItemPayload {
#[pb(index = 1)]
pub item_id: String,
#[pb(index = 2)]
pub from: i32,
#[pb(index = 3)]
pub to: i32,
#[pb(index = 4)]
pub ty: MoveFolderItemType,
}
pub struct MoveFolderItemParams {
pub item_id: String,
pub from: usize,
pub to: usize,
pub ty: MoveFolderItemType,
}
impl TryInto<MoveFolderItemParams> for MoveFolderItemPayload {
type Error = ErrorCode;
fn try_into(self) -> Result<MoveFolderItemParams, Self::Error> {
let view_id = ViewIdentify::parse(self.item_id)?.0;
Ok(MoveFolderItemParams {
item_id: view_id,
from: self.from as usize,
to: self.to as usize,
ty: self.ty,
})
}
}
// impl<'de> Deserialize<'de> for ViewDataType {
// fn deserialize<D>(deserializer: D) -> Result<Self, <D as Deserializer<'de>>::Error>
// where

View File

@ -2777,6 +2777,266 @@ impl ::protobuf::reflect::ProtobufValue for UpdateViewParams {
}
}
#[derive(PartialEq,Clone,Default)]
pub struct MoveFolderItemPayload {
// message fields
pub item_id: ::std::string::String,
pub from: i32,
pub to: i32,
pub ty: MoveFolderItemType,
// special fields
pub unknown_fields: ::protobuf::UnknownFields,
pub cached_size: ::protobuf::CachedSize,
}
impl<'a> ::std::default::Default for &'a MoveFolderItemPayload {
fn default() -> &'a MoveFolderItemPayload {
<MoveFolderItemPayload as ::protobuf::Message>::default_instance()
}
}
impl MoveFolderItemPayload {
pub fn new() -> MoveFolderItemPayload {
::std::default::Default::default()
}
// string item_id = 1;
pub fn get_item_id(&self) -> &str {
&self.item_id
}
pub fn clear_item_id(&mut self) {
self.item_id.clear();
}
// Param is passed by value, moved
pub fn set_item_id(&mut self, v: ::std::string::String) {
self.item_id = v;
}
// Mutable pointer to the field.
// If field is not initialized, it is initialized with default value first.
pub fn mut_item_id(&mut self) -> &mut ::std::string::String {
&mut self.item_id
}
// Take field
pub fn take_item_id(&mut self) -> ::std::string::String {
::std::mem::replace(&mut self.item_id, ::std::string::String::new())
}
// int32 from = 2;
pub fn get_from(&self) -> i32 {
self.from
}
pub fn clear_from(&mut self) {
self.from = 0;
}
// Param is passed by value, moved
pub fn set_from(&mut self, v: i32) {
self.from = v;
}
// int32 to = 3;
pub fn get_to(&self) -> i32 {
self.to
}
pub fn clear_to(&mut self) {
self.to = 0;
}
// Param is passed by value, moved
pub fn set_to(&mut self, v: i32) {
self.to = v;
}
// .MoveFolderItemType ty = 4;
pub fn get_ty(&self) -> MoveFolderItemType {
self.ty
}
pub fn clear_ty(&mut self) {
self.ty = MoveFolderItemType::MoveApp;
}
// Param is passed by value, moved
pub fn set_ty(&mut self, v: MoveFolderItemType) {
self.ty = v;
}
}
impl ::protobuf::Message for MoveFolderItemPayload {
fn is_initialized(&self) -> bool {
true
}
fn merge_from(&mut self, is: &mut ::protobuf::CodedInputStream<'_>) -> ::protobuf::ProtobufResult<()> {
while !is.eof()? {
let (field_number, wire_type) = is.read_tag_unpack()?;
match field_number {
1 => {
::protobuf::rt::read_singular_proto3_string_into(wire_type, is, &mut self.item_id)?;
},
2 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_int32()?;
self.from = tmp;
},
3 => {
if wire_type != ::protobuf::wire_format::WireTypeVarint {
return ::std::result::Result::Err(::protobuf::rt::unexpected_wire_type(wire_type));
}
let tmp = is.read_int32()?;
self.to = tmp;
},
4 => {
::protobuf::rt::read_proto3_enum_with_unknown_fields_into(wire_type, is, &mut self.ty, 4, &mut self.unknown_fields)?
},
_ => {
::protobuf::rt::read_unknown_or_skip_group(field_number, wire_type, is, self.mut_unknown_fields())?;
},
};
}
::std::result::Result::Ok(())
}
// Compute sizes of nested messages
#[allow(unused_variables)]
fn compute_size(&self) -> u32 {
let mut my_size = 0;
if !self.item_id.is_empty() {
my_size += ::protobuf::rt::string_size(1, &self.item_id);
}
if self.from != 0 {
my_size += ::protobuf::rt::value_size(2, self.from, ::protobuf::wire_format::WireTypeVarint);
}
if self.to != 0 {
my_size += ::protobuf::rt::value_size(3, self.to, ::protobuf::wire_format::WireTypeVarint);
}
if self.ty != MoveFolderItemType::MoveApp {
my_size += ::protobuf::rt::enum_size(4, self.ty);
}
my_size += ::protobuf::rt::unknown_fields_size(self.get_unknown_fields());
self.cached_size.set(my_size);
my_size
}
fn write_to_with_cached_sizes(&self, os: &mut ::protobuf::CodedOutputStream<'_>) -> ::protobuf::ProtobufResult<()> {
if !self.item_id.is_empty() {
os.write_string(1, &self.item_id)?;
}
if self.from != 0 {
os.write_int32(2, self.from)?;
}
if self.to != 0 {
os.write_int32(3, self.to)?;
}
if self.ty != MoveFolderItemType::MoveApp {
os.write_enum(4, ::protobuf::ProtobufEnum::value(&self.ty))?;
}
os.write_unknown_fields(self.get_unknown_fields())?;
::std::result::Result::Ok(())
}
fn get_cached_size(&self) -> u32 {
self.cached_size.get()
}
fn get_unknown_fields(&self) -> &::protobuf::UnknownFields {
&self.unknown_fields
}
fn mut_unknown_fields(&mut self) -> &mut ::protobuf::UnknownFields {
&mut self.unknown_fields
}
fn as_any(&self) -> &dyn (::std::any::Any) {
self as &dyn (::std::any::Any)
}
fn as_any_mut(&mut self) -> &mut dyn (::std::any::Any) {
self as &mut dyn (::std::any::Any)
}
fn into_any(self: ::std::boxed::Box<Self>) -> ::std::boxed::Box<dyn (::std::any::Any)> {
self
}
fn descriptor(&self) -> &'static ::protobuf::reflect::MessageDescriptor {
Self::descriptor_static()
}
fn new() -> MoveFolderItemPayload {
MoveFolderItemPayload::new()
}
fn descriptor_static() -> &'static ::protobuf::reflect::MessageDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::MessageDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
let mut fields = ::std::vec::Vec::new();
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeString>(
"item_id",
|m: &MoveFolderItemPayload| { &m.item_id },
|m: &mut MoveFolderItemPayload| { &mut m.item_id },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"from",
|m: &MoveFolderItemPayload| { &m.from },
|m: &mut MoveFolderItemPayload| { &mut m.from },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeInt32>(
"to",
|m: &MoveFolderItemPayload| { &m.to },
|m: &mut MoveFolderItemPayload| { &mut m.to },
));
fields.push(::protobuf::reflect::accessor::make_simple_field_accessor::<_, ::protobuf::types::ProtobufTypeEnum<MoveFolderItemType>>(
"ty",
|m: &MoveFolderItemPayload| { &m.ty },
|m: &mut MoveFolderItemPayload| { &mut m.ty },
));
::protobuf::reflect::MessageDescriptor::new_pb_name::<MoveFolderItemPayload>(
"MoveFolderItemPayload",
fields,
file_descriptor_proto()
)
})
}
fn default_instance() -> &'static MoveFolderItemPayload {
static instance: ::protobuf::rt::LazyV2<MoveFolderItemPayload> = ::protobuf::rt::LazyV2::INIT;
instance.get(MoveFolderItemPayload::new)
}
}
impl ::protobuf::Clear for MoveFolderItemPayload {
fn clear(&mut self) {
self.item_id.clear();
self.from = 0;
self.to = 0;
self.ty = MoveFolderItemType::MoveApp;
self.unknown_fields.clear();
}
}
impl ::std::fmt::Debug for MoveFolderItemPayload {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
::protobuf::text_format::fmt(self, f)
}
}
impl ::protobuf::reflect::ProtobufValue for MoveFolderItemPayload {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Message(self)
}
}
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum ViewDataType {
TextBlock = 0,
@ -2827,6 +3087,56 @@ impl ::protobuf::reflect::ProtobufValue for ViewDataType {
}
}
#[derive(Clone,PartialEq,Eq,Debug,Hash)]
pub enum MoveFolderItemType {
MoveApp = 0,
MoveView = 1,
}
impl ::protobuf::ProtobufEnum for MoveFolderItemType {
fn value(&self) -> i32 {
*self as i32
}
fn from_i32(value: i32) -> ::std::option::Option<MoveFolderItemType> {
match value {
0 => ::std::option::Option::Some(MoveFolderItemType::MoveApp),
1 => ::std::option::Option::Some(MoveFolderItemType::MoveView),
_ => ::std::option::Option::None
}
}
fn values() -> &'static [Self] {
static values: &'static [MoveFolderItemType] = &[
MoveFolderItemType::MoveApp,
MoveFolderItemType::MoveView,
];
values
}
fn enum_descriptor_static() -> &'static ::protobuf::reflect::EnumDescriptor {
static descriptor: ::protobuf::rt::LazyV2<::protobuf::reflect::EnumDescriptor> = ::protobuf::rt::LazyV2::INIT;
descriptor.get(|| {
::protobuf::reflect::EnumDescriptor::new_pb_name::<MoveFolderItemType>("MoveFolderItemType", file_descriptor_proto())
})
}
}
impl ::std::marker::Copy for MoveFolderItemType {
}
impl ::std::default::Default for MoveFolderItemType {
fn default() -> Self {
MoveFolderItemType::MoveApp
}
}
impl ::protobuf::reflect::ProtobufValue for MoveFolderItemType {
fn as_ref(&self) -> ::protobuf::reflect::ReflectValueRef {
::protobuf::reflect::ReflectValueRef::Enum(::protobuf::ProtobufEnum::descriptor(self))
}
}
static file_descriptor_proto_data: &'static [u8] = b"\
\n\nview.proto\"\xf5\x02\n\x04View\x12\x0e\n\x02id\x18\x01\x20\x01(\tR\
\x02id\x12\x20\n\x0cbelong_to_id\x18\x02\x20\x01(\tR\nbelongToId\x12\x12\
@ -2862,8 +3172,12 @@ static file_descriptor_proto_data: &'static [u8] = b"\
\n\x04name\x18\x02\x20\x01(\tH\0R\x04name\x12\x14\n\x04desc\x18\x03\x20\
\x01(\tH\x01R\x04desc\x12\x1e\n\tthumbnail\x18\x04\x20\x01(\tH\x02R\tthu\
mbnailB\r\n\x0bone_of_nameB\r\n\x0bone_of_descB\x12\n\x10one_of_thumbnai\
l*'\n\x0cViewDataType\x12\r\n\tTextBlock\x10\0\x12\x08\n\x04Grid\x10\x01\
b\x06proto3\
l\"y\n\x15MoveFolderItemPayload\x12\x17\n\x07item_id\x18\x01\x20\x01(\tR\
\x06itemId\x12\x12\n\x04from\x18\x02\x20\x01(\x05R\x04from\x12\x0e\n\x02\
to\x18\x03\x20\x01(\x05R\x02to\x12#\n\x02ty\x18\x04\x20\x01(\x0e2\x13.Mo\
veFolderItemTypeR\x02ty*'\n\x0cViewDataType\x12\r\n\tTextBlock\x10\0\x12\
\x08\n\x04Grid\x10\x01*/\n\x12MoveFolderItemType\x12\x0b\n\x07MoveApp\
\x10\0\x12\x0c\n\x08MoveView\x10\x01b\x06proto3\
";
static file_descriptor_proto_lazy: ::protobuf::rt::LazyV2<::protobuf::descriptor::FileDescriptorProto> = ::protobuf::rt::LazyV2::INIT;

View File

@ -54,7 +54,17 @@ message UpdateViewParams {
oneof one_of_desc { string desc = 3; };
oneof one_of_thumbnail { string thumbnail = 4; };
}
message MoveFolderItemPayload {
string item_id = 1;
int32 from = 2;
int32 to = 3;
MoveFolderItemType ty = 4;
}
enum ViewDataType {
TextBlock = 0;
Grid = 1;
}
enum MoveFolderItemType {
MoveApp = 0;
MoveView = 1;
}

View File

@ -235,6 +235,21 @@ impl FolderPad {
})
}
#[tracing::instrument(level = "trace", skip(self), err)]
pub fn move_view(&mut self, view_id: &str, _from: usize, to: usize) -> CollaborateResult<Option<FolderChange>> {
let view = self.read_view(view_id)?;
self.with_app(&view.belong_to_id, |app| {
match app.belongings.iter().position(|view| view.id == view_id) {
None => Ok(None),
Some(index) => {
let view = app.belongings.remove(index);
app.belongings.insert(to, view);
Ok(Some(()))
}
}
})
}
pub fn create_trash(&mut self, trash: Vec<Trash>) -> CollaborateResult<Option<FolderChange>> {
self.with_trash(|t| {
let mut new_trash = trash.into_iter().map(Arc::new).collect::<Vec<Arc<Trash>>>();