feat: use result instead of either (#4724)

* feat: use result instead of either

* chore: remove dartz
This commit is contained in:
Lucas.Xu
2024-02-24 20:54:10 +07:00
committed by GitHub
parent 236b5bfe90
commit 2abb396467
190 changed files with 1813 additions and 1527 deletions

View File

@ -6,7 +6,7 @@ import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class DocumentListener {
DocumentListener({
@ -36,13 +36,11 @@ class DocumentListener {
void _callback(
DocumentNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
switch (ty) {
case DocumentNotification.DidReceiveUpdate:
result
.swap()
.map((r) => didReceiveUpdate?.call(DocEventPB.fromBuffer(r)));
result.map((r) => didReceiveUpdate?.call(DocEventPB.fromBuffer(r)));
break;
default:
break;

View File

@ -6,7 +6,7 @@ import 'package:appflowy_backend/protobuf/flowy-document/protobuf.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class DocumentSyncStateListener {
DocumentSyncStateListener({
@ -34,11 +34,11 @@ class DocumentSyncStateListener {
void _callback(
DocumentNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
switch (ty) {
case DocumentNotification.DidUpdateDocumentSyncState:
result.swap().map(
result.map(
(r) {
final value = DocumentSyncStatePB.fromBuffer(r);
didReceiveSyncState?.call(value);

View File

@ -1,5 +1,4 @@
import 'package:appflowy/workspace/application/edit_panel/edit_context.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -10,10 +9,10 @@ class EditPanelBloc extends Bloc<EditPanelEvent, EditPanelState> {
on<EditPanelEvent>((event, emit) async {
await event.map(
startEdit: (e) async {
emit(state.copyWith(isEditing: true, editContext: some(e.context)));
emit(state.copyWith(isEditing: true, editContext: e.context));
},
endEdit: (value) async {
emit(state.copyWith(isEditing: false, editContext: none()));
emit(state.copyWith(isEditing: false, editContext: null));
},
);
});
@ -31,11 +30,11 @@ class EditPanelEvent with _$EditPanelEvent {
class EditPanelState with _$EditPanelState {
const factory EditPanelState({
required bool isEditing,
required Option<EditPanelContext> editContext,
required EditPanelContext? editContext,
}) = _EditPanelState;
factory EditPanelState.initial() => EditPanelState(
factory EditPanelState.initial() => const EditPanelState(
isEditing: false,
editContext: none(),
editContext: null,
);
}

View File

@ -7,7 +7,7 @@ import 'package:appflowy/plugins/document/presentation/editor_plugins/parsers/do
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
const List<NodeParser> _customParsers = [
@ -30,30 +30,35 @@ class DocumentExporter {
final ViewPB view;
Future<Either<FlowyError, String>> export(DocumentExportType type) async {
Future<FlowyResult<String, FlowyError>> export(
DocumentExportType type,
) async {
final documentService = DocumentService();
final result = await documentService.openDocument(viewId: view.id);
return result.fold((error) => left(error), (r) {
final document = r.toDocument();
if (document == null) {
return left(
FlowyError(
msg: LocaleKeys.settings_files_exportFileFail.tr(),
),
);
}
switch (type) {
case DocumentExportType.json:
return right(jsonEncode(document));
case DocumentExportType.markdown:
final markdown = documentToMarkdown(
document,
customParsers: _customParsers,
return result.fold(
(r) {
final document = r.toDocument();
if (document == null) {
return FlowyResult.failure(
FlowyError(
msg: LocaleKeys.settings_files_exportFileFail.tr(),
),
);
return right(markdown);
case DocumentExportType.text:
throw UnimplementedError();
}
});
}
switch (type) {
case DocumentExportType.json:
return FlowyResult.success(jsonEncode(document));
case DocumentExportType.markdown:
final markdown = documentToMarkdown(
document,
customParsers: _customParsers,
);
return FlowyResult.success(markdown);
case DocumentExportType.text:
throw UnimplementedError();
}
},
(error) => FlowyResult.failure(error),
);
}
}

View File

@ -2,7 +2,7 @@ import 'package:appflowy/workspace/application/favorite/favorite_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -69,14 +69,14 @@ class FavoriteBloc extends Bloc<FavoriteEvent, FavoriteState> {
}
void _onFavoritesUpdated(
Either<FlowyError, RepeatedViewPB> favoriteOrFailed,
FlowyResult<RepeatedViewPB, FlowyError> favoriteOrFailed,
bool didFavorite,
) {
favoriteOrFailed.fold(
(error) => Log.error(error),
(favorite) => didFavorite
? add(FavoriteEvent.didFavorite(favorite))
: add(FavoriteEvent.didUnfavorite(favorite)),
(error) => Log.error(error),
);
}
}

View File

@ -6,11 +6,11 @@ import 'package:appflowy_backend/protobuf/flowy-folder/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/foundation.dart';
typedef FavoriteUpdated = void Function(
Either<FlowyError, RepeatedViewPB> result,
FlowyResult<RepeatedViewPB, FlowyError> result,
bool isFavorite,
);
@ -35,7 +35,7 @@ class FavoriteListener {
void _observableCallback(
FolderNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
if (_favoriteUpdated == null) {
return;
@ -46,12 +46,12 @@ class FavoriteListener {
(payload) {
final view = RepeatedViewPB.fromBuffer(payload);
_favoriteUpdated!(
right(view),
FlowyResult.success(view),
isFavorite,
);
},
(error) => _favoriteUpdated!(
left(error),
FlowyResult.failure(error),
isFavorite,
),
);

View File

@ -1,14 +1,14 @@
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class FavoriteService {
Future<Either<RepeatedViewPB, FlowyError>> readFavorites() {
Future<FlowyResult<RepeatedViewPB, FlowyError>> readFavorites() {
return FolderEventReadFavorites().send();
}
Future<Either<Unit, FlowyError>> toggleFavorite(
Future<FlowyResult<void, FlowyError>> toggleFavorite(
String viewId,
bool favoriteStatus,
) async {

View File

@ -1,12 +1,12 @@
import 'dart:async';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
class HomeService {
Future<Either<ViewPB, FlowyError>> readApp({required String appId}) {
Future<FlowyResult<ViewPB, FlowyError>> readApp({required String appId}) {
final payload = ViewIdPB.create()..value = appId;
return FolderEventGetView(payload).send();

View File

@ -3,7 +3,6 @@ import 'package:appflowy/workspace/application/edit_panel/edit_context.dart';
import 'package:appflowy/workspace/application/settings/appearance/appearance_cubit.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart'
show WorkspaceSettingPB;
import 'package:dartz/dartz.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/time/duration.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -43,10 +42,10 @@ class HomeSettingBloc extends Bloc<HomeSettingEvent, HomeSettingState> {
await event.map(
initial: (_Initial value) {},
setEditPanel: (e) async {
emit(state.copyWith(panelContext: some(e.editContext)));
emit(state.copyWith(panelContext: e.editContext));
},
dismissEditPanel: (value) async {
emit(state.copyWith(panelContext: none()));
emit(state.copyWith(panelContext: null));
},
didReceiveWorkspaceSetting: (_DidReceiveWorkspaceSetting value) {
emit(state.copyWith(workspaceSetting: value.setting));
@ -139,7 +138,7 @@ class HomeSettingEvent with _$HomeSettingEvent {
@freezed
class HomeSettingState with _$HomeSettingState {
const factory HomeSettingState({
required Option<EditPanelContext> panelContext,
required EditPanelContext? panelContext,
required WorkspaceSettingPB workspaceSetting,
required bool unauthorized,
required bool isMenuCollapsed,
@ -156,7 +155,7 @@ class HomeSettingState with _$HomeSettingState {
double screenWidthPx,
) {
return HomeSettingState(
panelContext: none(),
panelContext: null,
workspaceSetting: workspaceSetting,
unauthorized: false,
isMenuCollapsed: appearanceSettingsState.isMenuCollapsed,

View File

@ -6,7 +6,7 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -52,16 +52,23 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
(app) => emit(state.copyWith(lastCreatedView: app)),
(error) {
Log.error(error);
emit(state.copyWith(successOrFailure: right(error)));
emit(
state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
);
},
);
},
didReceiveApps: (e) async {
emit(
e.appsOrFail.fold(
(views) =>
state.copyWith(views: views, successOrFailure: left(unit)),
(err) => state.copyWith(successOrFailure: right(err)),
(views) => state.copyWith(
views: views,
successOrFailure: FlowyResult.success(null),
),
(err) =>
state.copyWith(successOrFailure: FlowyResult.failure(err)),
),
);
},
@ -92,16 +99,16 @@ class MenuBloc extends Bloc<MenuEvent, MenuState> {
(views) => state.copyWith(views: views),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
return state.copyWith(successOrFailure: FlowyResult.failure(error));
},
),
);
}
void _handleAppsOrFail(Either<List<ViewPB>, FlowyError> appsOrFail) {
void _handleAppsOrFail(FlowyResult<List<ViewPB>, FlowyError> appsOrFail) {
appsOrFail.fold(
(apps) => add(MenuEvent.didReceiveApps(left(apps))),
(error) => add(MenuEvent.didReceiveApps(right(error))),
(apps) => add(MenuEvent.didReceiveApps(FlowyResult.success(apps))),
(error) => add(MenuEvent.didReceiveApps(FlowyResult.failure(error))),
);
}
}
@ -113,7 +120,7 @@ class MenuEvent with _$MenuEvent {
_CreateApp;
const factory MenuEvent.moveApp(int fromIndex, int toIndex) = _MoveApp;
const factory MenuEvent.didReceiveApps(
Either<List<ViewPB>, FlowyError> appsOrFail,
FlowyResult<List<ViewPB>, FlowyError> appsOrFail,
) = _ReceiveApps;
}
@ -121,12 +128,12 @@ class MenuEvent with _$MenuEvent {
class MenuState with _$MenuState {
const factory MenuState({
required List<ViewPB> views,
required Either<Unit, FlowyError> successOrFailure,
required FlowyResult<void, FlowyError> successOrFailure,
ViewPB? lastCreatedView,
}) = _MenuState;
factory MenuState.initial() => MenuState(
views: [],
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
);
}

View File

@ -4,7 +4,7 @@ import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -63,7 +63,9 @@ class MenuUserBloc extends Bloc<MenuUserEvent, MenuUserState> {
result.fold((l) => null, (error) => Log.error(error));
}
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
void _profileUpdated(
FlowyResult<UserProfilePB, FlowyError> userProfileOrFailed,
) {
if (isClosed) {
return;
}
@ -90,13 +92,13 @@ class MenuUserEvent with _$MenuUserEvent {
class MenuUserState with _$MenuUserState {
const factory MenuUserState({
required UserProfilePB userProfile,
required Option<List<WorkspacePB>> workspaces,
required Either<Unit, String> successOrFailure,
required List<WorkspacePB>? workspaces,
required FlowyResult<void, String> successOrFailure,
}) = _MenuUserState;
factory MenuUserState.initial(UserProfilePB userProfile) => MenuUserState(
userProfile: userProfile,
workspaces: none(),
successOrFailure: left(unit),
workspaces: null,
successOrFailure: FlowyResult.success(null),
);
}

View File

@ -6,11 +6,11 @@ import 'package:appflowy_backend/protobuf/flowy-folder/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/foundation.dart';
typedef RecentViewsUpdated = void Function(
Either<FlowyError, RepeatedViewIdPB> result,
FlowyResult<RepeatedViewIdPB, FlowyError> result,
);
class RecentViewsListener {
@ -34,7 +34,7 @@ class RecentViewsListener {
void _observableCallback(
FolderNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
if (_recentViewsUpdated == null) {
return;
@ -44,11 +44,11 @@ class RecentViewsListener {
(payload) {
final view = RepeatedViewIdPB.fromBuffer(payload);
_recentViewsUpdated?.call(
right(view),
FlowyResult.success(view),
);
},
(error) => _recentViewsUpdated?.call(
left(error),
FlowyResult.failure(error),
),
);
}

View File

@ -1,10 +1,10 @@
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class RecentService {
Future<Either<Unit, FlowyError>> updateRecentViews(
Future<FlowyResult<void, FlowyError>> updateRecentViews(
List<String> viewIds,
bool addInRecent,
) async {
@ -13,7 +13,7 @@ class RecentService {
).send();
}
Future<Either<RepeatedViewPB, FlowyError>> readRecentViews() {
Future<FlowyResult<RepeatedViewPB, FlowyError>> readRecentViews() {
return FolderEventReadRecentViews().send();
}
}

View File

@ -3,7 +3,7 @@ import 'package:appflowy/workspace/application/recent/recent_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -54,7 +54,7 @@ class RecentViewsBloc extends Bloc<RecentViewsEvent, RecentViewsState> {
}
void _onRecentViewsUpdated(
Either<FlowyError, RepeatedViewIdPB> result,
FlowyResult<RepeatedViewIdPB, FlowyError> result,
) {
add(const RecentViewsEvent.fetchRecentViews());
}

View File

@ -83,13 +83,11 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
Future<void> readTextScaleFactor() async {
final textScaleFactor = await getIt<KeyValueStorage>().getWithFormat(
KVKeys.textScaleFactor,
(value) => double.parse(value),
);
textScaleFactor.fold(
() => emit(state.copyWith(textScaleFactor: 1.0)),
(value) => emit(state.copyWith(textScaleFactor: value.clamp(0.7, 1.0))),
);
KVKeys.textScaleFactor,
(value) => double.parse(value),
) ??
1.0;
emit(state.copyWith(textScaleFactor: textScaleFactor.clamp(0.7, 1.0)));
}
/// Update selected theme in the user's settings and emit an updated state
@ -267,8 +265,8 @@ class AppearanceSettingsCubit extends Cubit<AppearanceSettingsState> {
final result = await UserSettingsBackendService()
.setDateTimeSettings(_dateTimeSettings);
result.fold(
(error) => Log.error(error),
(_) => null,
(error) => Log.error(error),
);
}

View File

@ -3,7 +3,7 @@ import 'package:appflowy/workspace/application/settings/cloud_setting_listener.d
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_setting.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -86,16 +86,18 @@ class AppFlowyCloudSettingState with _$AppFlowyCloudSettingState {
);
}
Either<String, ()> validateUrl(String url) {
FlowyResult<void, String> validateUrl(String url) {
try {
// Use Uri.parse to validate the url.
final uri = Uri.parse(url);
if (uri.isScheme('HTTP') || uri.isScheme('HTTPS')) {
return right(());
return FlowyResult.success(null);
} else {
return left(LocaleKeys.settings_menu_invalidCloudURLScheme.tr());
return FlowyResult.failure(
LocaleKeys.settings_menu_invalidCloudURLScheme.tr(),
);
}
} catch (e) {
return left(e.toString());
return FlowyResult.failure(e.toString());
}
}

View File

@ -2,7 +2,7 @@ import 'package:appflowy/env/backend_env.dart';
import 'package:appflowy/env/cloud_env.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -19,7 +19,7 @@ class AppFlowyCloudURLsBloc
emit(
state.copyWith(
updatedServerUrl: url,
urlError: none(),
urlError: null,
showRestartHint: url.isNotEmpty,
),
);
@ -29,9 +29,8 @@ class AppFlowyCloudURLsBloc
emit(
state.copyWith(
updatedServerUrl: "",
urlError: Some(
LocaleKeys.settings_menu_appFlowyCloudUrlCanNotBeEmpty.tr(),
),
urlError:
LocaleKeys.settings_menu_appFlowyCloudUrlCanNotBeEmpty.tr(),
restartApp: false,
),
);
@ -41,14 +40,14 @@ class AppFlowyCloudURLsBloc
await useSelfHostedAppFlowyCloudWithURL(url);
add(const AppFlowyCloudURLsEvent.didSaveConfig());
},
(err) => emit(state.copyWith(urlError: Some(err))),
(err) => emit(state.copyWith(urlError: err)),
);
}
},
didSaveConfig: () {
emit(
state.copyWith(
urlError: none(),
urlError: null,
restartApp: true,
),
);
@ -72,14 +71,14 @@ class AppFlowyCloudURLsState with _$AppFlowyCloudURLsState {
const factory AppFlowyCloudURLsState({
required AppFlowyCloudConfiguration config,
required String updatedServerUrl,
required Option<String> urlError,
required String? urlError,
required bool restartApp,
required bool showRestartHint,
}) = _AppFlowyCloudURLsState;
factory AppFlowyCloudURLsState.initial() => AppFlowyCloudURLsState(
config: getIt<AppFlowyCloudSharedEnv>().appflowyCloudConfig,
urlError: none(),
urlError: null,
updatedServerUrl:
getIt<AppFlowyCloudSharedEnv>().appflowyCloudConfig.base_url,
showRestartHint: getIt<AppFlowyCloudSharedEnv>()
@ -90,17 +89,19 @@ class AppFlowyCloudURLsState with _$AppFlowyCloudURLsState {
);
}
Either<String, String> validateUrl(String url) {
FlowyResult<String, String> validateUrl(String url) {
try {
// Use Uri.parse to validate the url.
final uri = Uri.parse(removeTrailingSlash(url));
if (uri.isScheme('HTTP') || uri.isScheme('HTTPS')) {
return left(uri.toString());
return FlowyResult.success(uri.toString());
} else {
return right(LocaleKeys.settings_menu_invalidCloudURLScheme.tr());
return FlowyResult.failure(
LocaleKeys.settings_menu_invalidCloudURLScheme.tr(),
);
}
} catch (e) {
return right(e.toString());
return FlowyResult.failure(e.toString());
}
}

View File

@ -64,14 +64,14 @@ class ApplicationDataStorage {
}
final response = await getIt<KeyValueStorage>().get(KVKeys.pathLocation);
String path = await response.fold(
() async {
// return the default path if the path is not set
final directory = await appFlowyApplicationDataDirectory();
return directory.path;
},
(path) => path,
);
String path;
if (response == null) {
final directory = await appFlowyApplicationDataDirectory();
path = directory.path;
} else {
path = response;
}
_cachePath = path;
// if the path is not exists means the path is invalid, so we should clear the kv store

View File

@ -5,7 +5,7 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import '../../../core/notification/user_notification.dart';
@ -14,10 +14,10 @@ class UserCloudConfigListener {
UserNotificationParser? _userParser;
StreamSubscription<SubscribeObject>? _subscription;
void Function(Either<CloudSettingPB, FlowyError>)? _onSettingChanged;
void Function(FlowyResult<CloudSettingPB, FlowyError>)? _onSettingChanged;
void start({
void Function(Either<CloudSettingPB, FlowyError>)? onSettingChanged,
void Function(FlowyResult<CloudSettingPB, FlowyError>)? onSettingChanged,
}) {
_onSettingChanged = onSettingChanged;
_userParser = UserNotificationParser(
@ -37,14 +37,14 @@ class UserCloudConfigListener {
void _userNotificationCallback(
UserNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
switch (ty) {
case UserNotification.DidUpdateCloudConfig:
result.fold(
(payload) =>
_onSettingChanged?.call(left(CloudSettingPB.fromBuffer(payload))),
(error) => _onSettingChanged?.call(right(error)),
(payload) => _onSettingChanged
?.call(FlowyResult.success(CloudSettingPB.fromBuffer(payload))),
(error) => _onSettingChanged?.call(FlowyResult.failure(error)),
);
break;
default:

View File

@ -21,9 +21,6 @@ class CreateFileSettingsCubit extends Cubit<bool> {
KVKeys.showRenameDialogWhenCreatingNewFile,
(value) => bool.parse(value),
);
settingsOrFailure.fold(
() => emit(false),
(settings) => emit(settings),
);
emit(settingsOrFailure ?? false);
}
}

View File

@ -47,8 +47,8 @@ class NotificationSettingsCubit extends Cubit<NotificationSettingsState> {
final result = await UserSettingsBackendService()
.setNotificationSettings(_notificationSettings);
result.fold(
(error) => Log.error(error),
(r) => null,
(error) => Log.error(error),
);
}
}

View File

@ -3,7 +3,7 @@ import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/import_data.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -36,8 +36,9 @@ class SettingFileImportBloc
(l) {
emit(
state.copyWith(
successOrFail: some(left(unit)),
loadingState: LoadingState.finish(left(unit)),
successOrFail: FlowyResult.success(null),
loadingState:
LoadingState.finish(FlowyResult.success(null)),
),
);
},
@ -45,8 +46,8 @@ class SettingFileImportBloc
Log.error(err);
emit(
state.copyWith(
successOrFail: some(right(err)),
loadingState: LoadingState.finish(right(err)),
successOrFail: FlowyResult.failure(err),
loadingState: LoadingState.finish(FlowyResult.failure(err)),
),
);
},
@ -63,7 +64,7 @@ class SettingFileImportEvent with _$SettingFileImportEvent {
const factory SettingFileImportEvent.importAppFlowyDataFolder(String path) =
_ImportAppFlowyDataFolder;
const factory SettingFileImportEvent.finishImport(
Either<Unit, FlowyError> result,
FlowyResult<void, FlowyError> result,
) = _ImportResult;
}
@ -71,11 +72,11 @@ class SettingFileImportEvent with _$SettingFileImportEvent {
class SettingFileImportState with _$SettingFileImportState {
const factory SettingFileImportState({
required LoadingState loadingState,
required Option<Either<Unit, FlowyError>> successOrFail,
required FlowyResult<void, FlowyError>? successOrFail,
}) = _SettingFileImportState;
factory SettingFileImportState.initial() => SettingFileImportState(
loadingState: const LoadingState.idle(),
successOrFail: none(),
factory SettingFileImportState.initial() => const SettingFileImportState(
loadingState: LoadingState.idle(),
successOrFail: null,
);
}

View File

@ -2,7 +2,7 @@ import 'package:appflowy/user/application/user_listener.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -53,7 +53,9 @@ class SettingsDialogBloc
);
}
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
void _profileUpdated(
FlowyResult<UserProfilePB, FlowyError> userProfileOrFailed,
) {
userProfileOrFailed.fold(
(newUserProfile) =>
add(SettingsDialogEvent.didReceiveUserProfile(newUserProfile)),
@ -76,14 +78,14 @@ class SettingsDialogEvent with _$SettingsDialogEvent {
class SettingsDialogState with _$SettingsDialogState {
const factory SettingsDialogState({
required UserProfilePB userProfile,
required Either<Unit, String> successOrFailure,
required FlowyResult<void, String> successOrFailure,
required SettingsPage page,
}) = _SettingsDialogState;
factory SettingsDialogState.initial(UserProfilePB userProfile) =>
SettingsDialogState(
userProfile: userProfile,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
page: SettingsPage.appearance,
);
}

View File

@ -2,10 +2,11 @@ import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/database_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/share_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class BackendExportService {
static Future<Either<DatabaseExportDataPB, FlowyError>> exportDatabaseAsCSV(
static Future<FlowyResult<DatabaseExportDataPB, FlowyError>>
exportDatabaseAsCSV(
String viewId,
) async {
final payload = DatabaseViewIdPB.create()..value = viewId;

View File

@ -2,10 +2,10 @@ import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/import.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pbenum.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class ImportBackendService {
static Future<Either<Unit, FlowyError>> importData(
static Future<FlowyResult<void, FlowyError>> importData(
List<int> data,
String name,
String parentViewId,

View File

@ -5,7 +5,7 @@ import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -56,7 +56,7 @@ class SupabaseCloudSettingBloc
emit(
state.copyWith(
setting: setting,
loadingState: LoadingState.finish(left(unit)),
loadingState: LoadingState.finish(FlowyResult.success(null)),
),
);
},
@ -96,7 +96,7 @@ class SupabaseCloudSettingState with _$SupabaseCloudSettingState {
factory SupabaseCloudSettingState.initial(CloudSettingPB setting) =>
SupabaseCloudSettingState(
loadingState: LoadingState.finish(left(unit)),
loadingState: LoadingState.finish(FlowyResult.success(null)),
setting: setting,
config: getIt<AppFlowyCloudSharedEnv>().supabaseConfig,
);

View File

@ -4,7 +4,6 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -23,7 +22,7 @@ class SupabaseCloudURLsBloc
state.copyWith(
updatedUrl: url,
showRestartHint: url.isNotEmpty && state.upatedAnonKey.isNotEmpty,
urlError: none(),
urlError: null,
),
);
},
@ -33,7 +32,7 @@ class SupabaseCloudURLsBloc
upatedAnonKey: anonKey,
showRestartHint:
anonKey.isNotEmpty && state.updatedUrl.isNotEmpty,
anonKeyError: none(),
anonKeyError: null,
),
);
},
@ -41,10 +40,9 @@ class SupabaseCloudURLsBloc
if (state.updatedUrl.isEmpty) {
emit(
state.copyWith(
urlError: Some(
LocaleKeys.settings_menu_cloudSupabaseUrlCanNotBeEmpty.tr(),
),
anonKeyError: none(),
urlError:
LocaleKeys.settings_menu_cloudSupabaseUrlCanNotBeEmpty.tr(),
anonKeyError: null,
restartApp: false,
),
);
@ -54,11 +52,10 @@ class SupabaseCloudURLsBloc
if (state.upatedAnonKey.isEmpty) {
emit(
state.copyWith(
urlError: none(),
anonKeyError: Some(
LocaleKeys.settings_menu_cloudSupabaseAnonKeyCanNotBeEmpty
.tr(),
),
urlError: null,
anonKeyError: LocaleKeys
.settings_menu_cloudSupabaseAnonKeyCanNotBeEmpty
.tr(),
restartApp: false,
),
);
@ -66,7 +63,6 @@ class SupabaseCloudURLsBloc
}
validateUrl(state.updatedUrl).fold(
(error) => emit(state.copyWith(urlError: Some(error))),
(_) async {
await useSupabaseCloud(
url: state.updatedUrl,
@ -75,13 +71,14 @@ class SupabaseCloudURLsBloc
add(const SupabaseCloudURLsEvent.didSaveConfig());
},
(error) => emit(state.copyWith(urlError: error)),
);
},
didSaveConfig: () {
emit(
state.copyWith(
urlError: none(),
anonKeyError: none(),
urlError: null,
anonKeyError: null,
restartApp: true,
),
);
@ -110,8 +107,8 @@ class SupabaseCloudURLsState with _$SupabaseCloudURLsState {
required SupabaseConfiguration config,
required String updatedUrl,
required String upatedAnonKey,
required Option<String> urlError,
required Option<String> anonKeyError,
required String? urlError,
required String? anonKeyError,
required bool restartApp,
required bool showRestartHint,
}) = _SupabaseCloudURLsState;
@ -121,8 +118,8 @@ class SupabaseCloudURLsState with _$SupabaseCloudURLsState {
return SupabaseCloudURLsState(
updatedUrl: config.url,
upatedAnonKey: config.anon_key,
urlError: none(),
anonKeyError: none(),
urlError: null,
anonKeyError: null,
restartApp: false,
showRestartHint: config.url.isNotEmpty && config.anon_key.isNotEmpty,
config: config,

View File

@ -5,6 +5,7 @@ import 'package:appflowy/core/config/kv_keys.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
part 'folder_bloc.freezed.dart';
enum FolderCategoryType {
@ -34,10 +35,10 @@ class FolderBloc extends Bloc<FolderEvent, FolderState> {
Future<void> _setFolderExpandStatus(bool isExpanded) async {
final result = await getIt<KeyValueStorage>().get(KVKeys.expandedViews);
final map = result.fold(
() => {},
(r) => jsonDecode(r),
);
var map = {};
if (result != null) {
map = jsonDecode(result);
}
if (isExpanded) {
// set expand status to true if it's not expanded
map[state.type.name] = true;
@ -50,10 +51,11 @@ class FolderBloc extends Bloc<FolderEvent, FolderState> {
Future<bool> _getFolderExpandStatus() async {
return getIt<KeyValueStorage>().get(KVKeys.expandedViews).then((result) {
return result.fold(() => true, (r) {
final map = jsonDecode(r);
return map[state.type.name] ?? true;
});
if (result == null) {
return true;
}
final map = jsonDecode(result);
return map[state.type.name] ?? true;
});
}
}

View File

@ -3,7 +3,7 @@ import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -101,15 +101,17 @@ class SettingsUserViewBloc extends Bloc<SettingsUserEvent, SettingsUserState> {
}
result.fold(
(err) => Log.error(err),
(userProfile) => add(
SettingsUserEvent.didReceiveUserProfile(userProfile),
),
(err) => Log.error(err),
);
});
}
void _profileUpdated(Either<UserProfilePB, FlowyError> userProfileOrFailed) {
void _profileUpdated(
FlowyResult<UserProfilePB, FlowyError> userProfileOrFailed,
) {
userProfileOrFailed.fold(
(newUserProfile) {
add(SettingsUserEvent.didReceiveUserProfile(newUserProfile));
@ -141,12 +143,12 @@ class SettingsUserEvent with _$SettingsUserEvent {
class SettingsUserState with _$SettingsUserState {
const factory SettingsUserState({
required UserProfilePB userProfile,
required Either<Unit, String> successOrFailure,
required FlowyResult<void, String> successOrFailure,
}) = _SettingsUserState;
factory SettingsUserState.initial(UserProfilePB userProfile) =>
SettingsUserState(
userProfile: userProfile,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
);
}

View File

@ -9,8 +9,8 @@ import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:collection/collection.dart';
import 'package:dartz/dartz.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
import 'package:protobuf/protobuf.dart';
@ -45,7 +45,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
initial: (e) async {
listener.start(
onViewUpdated: (result) {
add(ViewEvent.viewDidUpdate(left(result)));
add(ViewEvent.viewDidUpdate(FlowyResult.success(result)));
},
onViewChildViewsUpdated: (result) async {
final view = await _updateChildViews(result);
@ -56,13 +56,20 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
);
favoriteListener.start(
favoritesUpdated: (result, isFavorite) {
result.fold((error) {}, (result) {
final current = result.items
.firstWhereOrNull((v) => v.id == state.view.id);
if (current != null) {
add(ViewEvent.viewDidUpdate(left(current)));
}
});
result.fold(
(result) {
final current = result.items
.firstWhereOrNull((v) => v.id == state.view.id);
if (current != null) {
add(
ViewEvent.viewDidUpdate(
FlowyResult.success(current),
),
);
}
},
(error) {},
);
},
);
final isExpanded = await _getViewIsExpanded(view);
@ -95,12 +102,12 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
emit(
state.copyWith(
view: view_ ?? view,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
),
);
},
(error) => emit(
state.copyWith(successOrFailure: right(error)),
state.copyWith(successOrFailure: FlowyResult.failure(error)),
),
);
},
@ -118,11 +125,13 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
(b) => b.name = e.newName,
);
return state.copyWith(
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
view: newView,
);
},
(error) => state.copyWith(successOrFailure: right(error)),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
),
);
},
@ -130,8 +139,11 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
final result = await ViewBackendService.delete(viewId: view.id);
emit(
result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
(l) =>
state.copyWith(successOrFailure: FlowyResult.success(null)),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
),
);
await RecentService().updateRecentViews([view.id], false);
@ -140,8 +152,11 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
final result = await ViewBackendService.duplicate(view: view);
emit(
result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
(l) =>
state.copyWith(successOrFailure: FlowyResult.success(null)),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
),
);
},
@ -153,8 +168,11 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
);
emit(
result.fold(
(l) => state.copyWith(successOrFailure: left(unit)),
(error) => state.copyWith(successOrFailure: right(error)),
(l) =>
state.copyWith(successOrFailure: FlowyResult.success(null)),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
),
);
},
@ -172,9 +190,11 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
result.fold(
(view) => state.copyWith(
lastCreatedView: view,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
(error) => state.copyWith(successOrFailure: right(error)),
),
);
},
@ -225,7 +245,7 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
},
(error) => emit(
state.copyWith(
successOrFailure: right(error),
successOrFailure: FlowyResult.failure(error),
isExpanded: true,
isLoading: false,
),
@ -235,10 +255,12 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
Future<void> _setViewIsExpanded(ViewPB view, bool isExpanded) async {
final result = await getIt<KeyValueStorage>().get(KVKeys.expandedViews);
final map = result.fold(
() => {},
(r) => jsonDecode(r),
);
final Map map;
if (result != null) {
map = jsonDecode(result);
} else {
map = {};
}
if (isExpanded) {
map[view.id] = true;
} else {
@ -249,10 +271,11 @@ class ViewBloc extends Bloc<ViewEvent, ViewState> {
Future<bool> _getViewIsExpanded(ViewPB view) {
return getIt<KeyValueStorage>().get(KVKeys.expandedViews).then((result) {
return result.fold(() => false, (r) {
final map = jsonDecode(r);
return map[view.id] ?? false;
});
if (result == null) {
return false;
}
final map = jsonDecode(result);
return map[view.id] ?? false;
});
}
@ -337,8 +360,9 @@ class ViewEvent with _$ViewEvent {
/// open the view after created
@Default(true) bool openAfterCreated,
}) = CreateView;
const factory ViewEvent.viewDidUpdate(Either<ViewPB, FlowyError> result) =
ViewDidUpdate;
const factory ViewEvent.viewDidUpdate(
FlowyResult<ViewPB, FlowyError> result,
) = ViewDidUpdate;
const factory ViewEvent.viewUpdateChildView(ViewPB result) =
ViewUpdateChildView;
}
@ -349,7 +373,7 @@ class ViewState with _$ViewState {
required ViewPB view,
required bool isEditing,
required bool isExpanded,
required Either<Unit, FlowyError> successOrFailure,
required FlowyResult<void, FlowyError> successOrFailure,
@Default(true) bool isLoading,
@Default(null) ViewPB? lastCreatedView,
}) = _ViewState;
@ -358,6 +382,6 @@ class ViewState with _$ViewState {
view: view,
isExpanded: false,
isEditing: false,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
);
}

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/board/presentation/board_page.dart';
import 'package:appflowy/plugins/database/calendar/presentation/calendar_page.dart';
@ -12,7 +10,8 @@ import 'package:appflowy/workspace/application/view/view_service.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:dartz/dartz.dart' hide id;
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter/material.dart';
enum FlowyPlugin {
editor,
@ -93,13 +92,13 @@ extension ViewExtension on ViewPB {
final ancestors = <ViewPB>[];
if (includeSelf) {
final self = await ViewBackendService.getView(id);
ancestors.add(self.getLeftOrNull<ViewPB>() ?? this);
ancestors.add(self.fold((s) => s, (e) => this));
}
Either<ViewPB, FlowyError> parent =
FlowyResult<ViewPB, FlowyError> parent =
await ViewBackendService.getView(parentViewId);
while (parent.isLeft()) {
while (parent.isSuccess()) {
// parent is not null
final view = parent.getLeftOrNull<ViewPB>();
final view = parent.fold((s) => s, (e) => null);
if (view == null || (!includeRoot && view.parentViewId.isEmpty)) {
break;
}

View File

@ -1,22 +1,23 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:appflowy/core/notification/folder_notification.dart';
import 'package:appflowy_backend/log.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-notification/subject.pb.dart';
import 'package:appflowy_backend/rust_stream.dart';
import 'package:appflowy_result/appflowy_result.dart';
// Delete the view from trash, which means the view was deleted permanently
typedef DeleteViewNotifyValue = Either<ViewPB, FlowyError>;
typedef DeleteViewNotifyValue = FlowyResult<ViewPB, FlowyError>;
// The view get updated
typedef UpdateViewNotifiedValue = ViewPB;
// Restore the view from trash
typedef RestoreViewNotifiedValue = Either<ViewPB, FlowyError>;
typedef RestoreViewNotifiedValue = FlowyResult<ViewPB, FlowyError>;
// Move the view to trash
typedef MoveToTrashNotifiedValue = Either<DeletedViewPB, FlowyError>;
typedef MoveToTrashNotifiedValue = FlowyResult<DeletedViewPB, FlowyError>;
class ViewListener {
ViewListener({required this.viewId});
@ -63,7 +64,7 @@ class ViewListener {
void _handleObservableType(
FolderNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
switch (ty) {
case FolderNotification.DidUpdateView:
@ -86,22 +87,23 @@ class ViewListener {
break;
case FolderNotification.DidDeleteView:
result.fold(
(payload) => _deletedNotifier?.call(left(ViewPB.fromBuffer(payload))),
(error) => _deletedNotifier?.call(right(error)),
(payload) => _deletedNotifier
?.call(FlowyResult.success(ViewPB.fromBuffer(payload))),
(error) => _deletedNotifier?.call(FlowyResult.failure(error)),
);
break;
case FolderNotification.DidRestoreView:
result.fold(
(payload) =>
_restoredNotifier?.call(left(ViewPB.fromBuffer(payload))),
(error) => _restoredNotifier?.call(right(error)),
(payload) => _restoredNotifier
?.call(FlowyResult.success(ViewPB.fromBuffer(payload))),
(error) => _restoredNotifier?.call(FlowyResult.failure(error)),
);
break;
case FolderNotification.DidMoveViewToTrash:
result.fold(
(payload) => _moveToTrashNotifier
?.call(left(DeletedViewPB.fromBuffer(payload))),
(error) => _moveToTrashNotifier?.call(right(error)),
?.call(FlowyResult.success(DeletedViewPB.fromBuffer(payload))),
(error) => _moveToTrashNotifier?.call(FlowyResult.failure(error)),
);
break;
default:

View File

@ -3,10 +3,10 @@ import 'dart:async';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
class ViewBackendService {
static Future<Either<ViewPB, FlowyError>> createView({
static Future<FlowyResult<ViewPB, FlowyError>> createView({
/// The [layoutType] is the type of the view.
required ViewLayoutPB layoutType,
@ -64,7 +64,7 @@ class ViewBackendService {
/// The orphan view is meant to be a view that is not attached to any parent view. By default, this
/// view will not be shown in the view list unless it is attached to a parent view that is shown in
/// the view list.
static Future<Either<ViewPB, FlowyError>> createOrphanView({
static Future<FlowyResult<ViewPB, FlowyError>> createOrphanView({
required String viewId,
required ViewLayoutPB layoutType,
required String name,
@ -84,7 +84,7 @@ class ViewBackendService {
return FolderEventCreateOrphanView(payload).send();
}
static Future<Either<ViewPB, FlowyError>> createDatabaseLinkedView({
static Future<FlowyResult<ViewPB, FlowyError>> createDatabaseLinkedView({
required String parentViewId,
required String databaseId,
required ViewLayoutPB layoutType,
@ -101,39 +101,47 @@ class ViewBackendService {
}
/// Returns a list of views that are the children of the given [viewId].
static Future<Either<List<ViewPB>, FlowyError>> getChildViews({
static Future<FlowyResult<List<ViewPB>, FlowyError>> getChildViews({
required String viewId,
}) {
final payload = ViewIdPB.create()..value = viewId;
return FolderEventGetView(payload).send().then((result) {
return result.fold(
(view) => left(view.childViews),
(error) => right(error),
(view) => FlowyResult.success(view.childViews),
(error) => FlowyResult.failure(error),
);
});
}
static Future<Either<Unit, FlowyError>> delete({required String viewId}) {
static Future<FlowyResult<void, FlowyError>> delete({
required String viewId,
}) {
final request = RepeatedViewIdPB.create()..items.add(viewId);
return FolderEventDeleteView(request).send();
}
static Future<Either<Unit, FlowyError>> deleteView({required String viewId}) {
static Future<FlowyResult<void, FlowyError>> deleteView({
required String viewId,
}) {
final request = RepeatedViewIdPB.create()..items.add(viewId);
return FolderEventDeleteView(request).send();
}
static Future<Either<Unit, FlowyError>> duplicate({required ViewPB view}) {
static Future<FlowyResult<void, FlowyError>> duplicate({
required ViewPB view,
}) {
return FolderEventDuplicateView(view).send();
}
static Future<Either<Unit, FlowyError>> favorite({required String viewId}) {
static Future<FlowyResult<void, FlowyError>> favorite({
required String viewId,
}) {
final request = RepeatedViewIdPB.create()..items.add(viewId);
return FolderEventToggleFavorite(request).send();
}
static Future<Either<ViewPB, FlowyError>> updateView({
static Future<FlowyResult<ViewPB, FlowyError>> updateView({
required String viewId,
String? name,
bool? isFavorite,
@ -151,7 +159,7 @@ class ViewBackendService {
return FolderEventUpdateView(payload).send();
}
static Future<Either<Unit, FlowyError>> updateViewIcon({
static Future<FlowyResult<void, FlowyError>> updateViewIcon({
required String viewId,
required String viewIcon,
}) {
@ -166,7 +174,7 @@ class ViewBackendService {
}
// deprecated
static Future<Either<Unit, FlowyError>> moveView({
static Future<FlowyResult<void, FlowyError>> moveView({
required String viewId,
required int fromIndex,
required int toIndex,
@ -183,7 +191,7 @@ class ViewBackendService {
///
/// supports nested view
/// if the [prevViewId] is null, the view will be moved to the beginning of the list
static Future<Either<Unit, FlowyError>> moveViewV2({
static Future<FlowyResult<void, FlowyError>> moveViewV2({
required String viewId,
required String newParentId,
required String? prevViewId,
@ -214,7 +222,7 @@ class ViewBackendService {
Future<List<ViewPB>> fetchViews() async {
final result = <ViewPB>[];
return FolderEventReadCurrentWorkspace().send().then((value) async {
final workspace = value.getLeftOrNull<WorkspacePB>();
final workspace = value.toNullable();
if (workspace != null) {
final views = workspace.views;
for (final view in views) {
@ -230,7 +238,7 @@ class ViewBackendService {
Future<List<ViewPB>> getAllViews(ViewPB view) async {
final result = <ViewPB>[];
final childViews = await getChildViews(viewId: view.id).then(
(value) => value.getLeftOrNull<List<ViewPB>>()?.toList(),
(value) => value.toNullable(),
);
if (childViews != null && childViews.isNotEmpty) {
result.addAll(childViews);
@ -242,35 +250,25 @@ class ViewBackendService {
return result;
}
static Future<Either<ViewPB, FlowyError>> getView(
static Future<FlowyResult<ViewPB, FlowyError>> getView(
String viewID,
) async {
final payload = ViewIdPB.create()..value = viewID;
return FolderEventGetView(payload).send();
}
Future<Either<ViewPB, FlowyError>> getChildView({
Future<FlowyResult<ViewPB, FlowyError>> getChildView({
required String parentViewId,
required String childViewId,
}) async {
final payload = ViewIdPB.create()..value = parentViewId;
return FolderEventGetView(payload).send().then((result) {
return result.fold(
(app) => left(
(app) => FlowyResult.success(
app.childViews.firstWhere((e) => e.id == childViewId),
),
(error) => right(error),
(error) => FlowyResult.failure(error),
);
});
}
}
extension AppFlowy on Either {
T? getLeftOrNull<T>() {
if (isLeft()) {
final result = fold<T?>((l) => l, (r) => null);
return result;
}
return null;
}
}

View File

@ -2,7 +2,7 @@ import 'package:appflowy/user/application/user_service.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:freezed_annotation/freezed_annotation.dart';
@ -25,14 +25,16 @@ class WorkspaceBloc extends Bloc<WorkspaceEvent, WorkspaceState> {
createWorkspace: (e) async {
await _createWorkspace(e.name, e.desc, emit);
},
workspacesReveived: (e) async {
workspacesReceived: (e) async {
emit(
e.workspacesOrFail.fold(
(workspaces) => state.copyWith(
workspaces: workspaces,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
),
(error) => state.copyWith(
successOrFailure: FlowyResult.failure(error),
),
(error) => state.copyWith(successOrFailure: right(error)),
),
);
},
@ -47,11 +49,11 @@ class WorkspaceBloc extends Bloc<WorkspaceEvent, WorkspaceState> {
workspacesOrFailed.fold(
(workspaces) => state.copyWith(
workspaces: workspaces,
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
),
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
return state.copyWith(successOrFailure: FlowyResult.failure(error));
},
),
);
@ -66,11 +68,11 @@ class WorkspaceBloc extends Bloc<WorkspaceEvent, WorkspaceState> {
emit(
result.fold(
(workspace) {
return state.copyWith(successOrFailure: left(unit));
return state.copyWith(successOrFailure: FlowyResult.success(null));
},
(error) {
Log.error(error);
return state.copyWith(successOrFailure: right(error));
return state.copyWith(successOrFailure: FlowyResult.failure(error));
},
),
);
@ -82,8 +84,8 @@ class WorkspaceEvent with _$WorkspaceEvent {
const factory WorkspaceEvent.initial() = Initial;
const factory WorkspaceEvent.createWorkspace(String name, String desc) =
CreateWorkspace;
const factory WorkspaceEvent.workspacesReveived(
Either<List<WorkspacePB>, FlowyError> workspacesOrFail,
const factory WorkspaceEvent.workspacesReceived(
FlowyResult<List<WorkspacePB>, FlowyError> workspacesOrFail,
) = WorkspacesReceived;
}
@ -92,12 +94,12 @@ class WorkspaceState with _$WorkspaceState {
const factory WorkspaceState({
required bool isLoading,
required List<WorkspacePB> workspaces,
required Either<Unit, FlowyError> successOrFailure,
required FlowyResult<void, FlowyError> successOrFailure,
}) = _WorkspaceState;
factory WorkspaceState.initial() => WorkspaceState(
isLoading: false,
workspaces: List.empty(),
successOrFailure: left(unit),
successOrFailure: FlowyResult.success(null),
);
}

View File

@ -1,17 +1,18 @@
import 'dart:async';
import 'dart:typed_data';
import 'package:appflowy/core/notification/folder_notification.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:dartz/dartz.dart';
import 'package:flowy_infra/notifier.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB;
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/notification.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart'
show UserProfilePB;
import 'package:appflowy_result/appflowy_result.dart';
import 'package:flowy_infra/notifier.dart';
typedef AppListNotifyValue = Either<List<ViewPB>, FlowyError>;
typedef WorkspaceNotifyValue = Either<WorkspacePB, FlowyError>;
typedef AppListNotifyValue = FlowyResult<List<ViewPB>, FlowyError>;
typedef WorkspaceNotifyValue = FlowyResult<WorkspacePB, FlowyError>;
class WorkspaceListener {
WorkspaceListener({required this.user, required this.workspaceId});
@ -45,21 +46,22 @@ class WorkspaceListener {
void _handleObservableType(
FolderNotification ty,
Either<Uint8List, FlowyError> result,
FlowyResult<Uint8List, FlowyError> result,
) {
switch (ty) {
case FolderNotification.DidUpdateWorkspace:
result.fold(
(payload) => _workspaceUpdatedNotifier?.value =
left(WorkspacePB.fromBuffer(payload)),
(error) => _workspaceUpdatedNotifier?.value = right(error),
FlowyResult.success(WorkspacePB.fromBuffer(payload)),
(error) =>
_workspaceUpdatedNotifier?.value = FlowyResult.failure(error),
);
break;
case FolderNotification.DidUpdateWorkspaceViews:
result.fold(
(payload) => _appsChangedNotifier?.value =
left(RepeatedViewPB.fromBuffer(payload).items),
(error) => _appsChangedNotifier?.value = right(error),
FlowyResult.success(RepeatedViewPB.fromBuffer(payload).items),
(error) => _appsChangedNotifier?.value = FlowyResult.failure(error),
);
break;
default:

View File

@ -1,18 +1,18 @@
import 'dart:async';
import 'package:dartz/dartz.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'
show CreateViewPayloadPB, MoveViewPayloadPB, ViewLayoutPB, ViewPB;
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
import 'package:appflowy_result/appflowy_result.dart';
class WorkspaceService {
WorkspaceService({required this.workspaceId});
final String workspaceId;
Future<Either<ViewPB, FlowyError>> createApp({
Future<FlowyResult<ViewPB, FlowyError>> createApp({
required String name,
String? desc,
int? index,
@ -33,21 +33,21 @@ class WorkspaceService {
return FolderEventCreateView(payload).send();
}
Future<Either<WorkspacePB, FlowyError>> getWorkspace() {
Future<FlowyResult<WorkspacePB, FlowyError>> getWorkspace() {
return FolderEventReadCurrentWorkspace().send();
}
Future<Either<List<ViewPB>, FlowyError>> getViews() {
Future<FlowyResult<List<ViewPB>, FlowyError>> getViews() {
final payload = WorkspaceIdPB.create()..value = workspaceId;
return FolderEventReadWorkspaceViews(payload).send().then((result) {
return result.fold(
(views) => left(views.items),
(error) => right(error),
(views) => FlowyResult.success(views.items),
(error) => FlowyResult.failure(error),
);
});
}
Future<Either<Unit, FlowyError>> moveApp({
Future<FlowyResult<void, FlowyError>> moveApp({
required String appId,
required int fromIndex,
required int toIndex,