mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: support leaving workspace (#5007)
This commit is contained in:
parent
dc8f632e3e
commit
0e7b3c7db2
@ -5,12 +5,16 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
extension AFRolePBExtension on AFRolePB {
|
extension AFRolePBExtension on AFRolePB {
|
||||||
bool get isOwner => this == AFRolePB.Owner;
|
bool get isOwner => this == AFRolePB.Owner;
|
||||||
|
|
||||||
|
bool get isMember => this == AFRolePB.Member;
|
||||||
|
|
||||||
bool get canInvite => isOwner;
|
bool get canInvite => isOwner;
|
||||||
|
|
||||||
bool get canDelete => isOwner;
|
bool get canDelete => isOwner;
|
||||||
|
|
||||||
bool get canUpdate => isOwner;
|
bool get canUpdate => isOwner;
|
||||||
|
|
||||||
|
bool get canLeave => this != AFRolePB.Owner;
|
||||||
|
|
||||||
String get description {
|
String get description {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case AFRolePB.Owner:
|
case AFRolePB.Owner:
|
||||||
|
@ -190,4 +190,11 @@ class UserBackendService {
|
|||||||
..role = role;
|
..role = role;
|
||||||
return UserEventUpdateWorkspaceMember(data).send();
|
return UserEventUpdateWorkspaceMember(data).send();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<FlowyResult<void, FlowyError>> leaveWorkspace(
|
||||||
|
String workspaceId,
|
||||||
|
) async {
|
||||||
|
final data = UserWorkspaceIdPB.create()..workspaceId = workspaceId;
|
||||||
|
return UserEventLeaveWorkspace(data).send();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -218,6 +218,30 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
leaveWorkspace: (workspaceId) async {
|
||||||
|
final result = await _userService.leaveWorkspace(workspaceId);
|
||||||
|
final workspaces = result.fold(
|
||||||
|
(s) => state.workspaces
|
||||||
|
.where((e) => e.workspaceId != workspaceId)
|
||||||
|
.toList(),
|
||||||
|
(e) => state.workspaces,
|
||||||
|
);
|
||||||
|
result.onSuccess((_) {
|
||||||
|
// if leaving the current workspace, open the first workspace
|
||||||
|
if (state.currentWorkspace?.workspaceId == workspaceId) {
|
||||||
|
add(OpenWorkspace(workspaces.first.workspaceId));
|
||||||
|
}
|
||||||
|
});
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
workspaces: workspaces,
|
||||||
|
actionResult: UserWorkspaceActionResult(
|
||||||
|
actionType: UserWorkspaceActionType.leave,
|
||||||
|
result: result,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -270,6 +294,8 @@ class UserWorkspaceEvent with _$UserWorkspaceEvent {
|
|||||||
String workspaceId,
|
String workspaceId,
|
||||||
String icon,
|
String icon,
|
||||||
) = _UpdateWorkspaceIcon;
|
) = _UpdateWorkspaceIcon;
|
||||||
|
const factory UserWorkspaceEvent.leaveWorkspace(String workspaceId) =
|
||||||
|
LeaveWorkspace;
|
||||||
}
|
}
|
||||||
|
|
||||||
enum UserWorkspaceActionType {
|
enum UserWorkspaceActionType {
|
||||||
@ -279,7 +305,8 @@ enum UserWorkspaceActionType {
|
|||||||
open,
|
open,
|
||||||
rename,
|
rename,
|
||||||
updateIcon,
|
updateIcon,
|
||||||
fetchWorkspaces;
|
fetchWorkspaces,
|
||||||
|
leave;
|
||||||
}
|
}
|
||||||
|
|
||||||
class UserWorkspaceActionResult {
|
class UserWorkspaceActionResult {
|
||||||
|
@ -112,6 +112,7 @@ class SidebarWorkspace extends StatelessWidget {
|
|||||||
break;
|
break;
|
||||||
case UserWorkspaceActionType.none:
|
case UserWorkspaceActionType.none:
|
||||||
case UserWorkspaceActionType.fetchWorkspaces:
|
case UserWorkspaceActionType.fetchWorkspaces:
|
||||||
|
case UserWorkspaceActionType.leave:
|
||||||
message = null;
|
message = null;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,8 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:appflowy/shared/af_role_pb_extension.dart';
|
||||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/settings/widgets/members/workspace_member_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||||
@ -13,6 +15,7 @@ import 'package:flutter_bloc/flutter_bloc.dart';
|
|||||||
enum WorkspaceMoreAction {
|
enum WorkspaceMoreAction {
|
||||||
rename,
|
rename,
|
||||||
delete,
|
delete,
|
||||||
|
leave,
|
||||||
}
|
}
|
||||||
|
|
||||||
class WorkspaceMoreActionList extends StatelessWidget {
|
class WorkspaceMoreActionList extends StatelessWidget {
|
||||||
@ -25,9 +28,20 @@ class WorkspaceMoreActionList extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final myRole = context.read<WorkspaceMemberBloc>().state.myRole;
|
||||||
|
final actions = [];
|
||||||
|
if (myRole.isOwner) {
|
||||||
|
actions.add(WorkspaceMoreAction.rename);
|
||||||
|
actions.add(WorkspaceMoreAction.delete);
|
||||||
|
} else if (myRole.canLeave) {
|
||||||
|
actions.add(WorkspaceMoreAction.leave);
|
||||||
|
}
|
||||||
|
if (actions.isEmpty) {
|
||||||
|
return const SizedBox.shrink();
|
||||||
|
}
|
||||||
return PopoverActionList<_WorkspaceMoreActionWrapper>(
|
return PopoverActionList<_WorkspaceMoreActionWrapper>(
|
||||||
direction: PopoverDirection.bottomWithCenterAligned,
|
direction: PopoverDirection.bottomWithCenterAligned,
|
||||||
actions: WorkspaceMoreAction.values
|
actions: actions
|
||||||
.map((e) => _WorkspaceMoreActionWrapper(e, workspace))
|
.map((e) => _WorkspaceMoreActionWrapper(e, workspace))
|
||||||
.toList(),
|
.toList(),
|
||||||
buildChild: (controller) {
|
buildChild: (controller) {
|
||||||
@ -92,6 +106,20 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
).show(context);
|
).show(context);
|
||||||
|
case WorkspaceMoreAction.leave:
|
||||||
|
await showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (_) => NavigatorOkCancelDialog(
|
||||||
|
title: LocaleKeys.workspace_leaveCurrentWorkspace.tr(),
|
||||||
|
message: LocaleKeys.workspace_leaveCurrentWorkspacePrompt.tr(),
|
||||||
|
onOkPressed: () {
|
||||||
|
workspaceBloc.add(
|
||||||
|
UserWorkspaceEvent.leaveWorkspace(workspace.workspaceId),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
okTitle: LocaleKeys.button_yes.tr(),
|
||||||
|
),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -103,6 +131,8 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
|
|||||||
return LocaleKeys.button_delete.tr();
|
return LocaleKeys.button_delete.tr();
|
||||||
case WorkspaceMoreAction.rename:
|
case WorkspaceMoreAction.rename:
|
||||||
return LocaleKeys.button_rename.tr();
|
return LocaleKeys.button_rename.tr();
|
||||||
|
case WorkspaceMoreAction.leave:
|
||||||
|
return LocaleKeys.workspace_leaveCurrentWorkspace.tr();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/af_role_pb_extension.dart';
|
|
||||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_actions.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/workspace/_sidebar_workspace_icon.dart';
|
||||||
@ -201,7 +200,6 @@ class WorkspaceMenuItem extends StatelessWidget {
|
|||||||
|
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
if (context.read<WorkspaceMemberBloc>().state.myRole.isOwner)
|
|
||||||
WorkspaceMoreActionList(workspace: workspace),
|
WorkspaceMoreActionList(workspace: workspace),
|
||||||
const FlowySvg(
|
const FlowySvg(
|
||||||
FlowySvgs.blue_check_s,
|
FlowySvgs.blue_check_s,
|
||||||
|
@ -79,7 +79,9 @@
|
|||||||
"updateIconSuccess": "Updated workspace icon successfully",
|
"updateIconSuccess": "Updated workspace icon successfully",
|
||||||
"updateIconFailed": "Updated workspace icon failed",
|
"updateIconFailed": "Updated workspace icon failed",
|
||||||
"cannotDeleteTheOnlyWorkspace": "Cannot delete the only workspace",
|
"cannotDeleteTheOnlyWorkspace": "Cannot delete the only workspace",
|
||||||
"fetchWorkspacesFailed": "Failed to fetch workspaces"
|
"fetchWorkspacesFailed": "Failed to fetch workspaces",
|
||||||
|
"leaveCurrentWorkspace": "Leave workspace",
|
||||||
|
"leaveCurrentWorkspacePrompt": "Are you sure you want to leave the current workspace?"
|
||||||
},
|
},
|
||||||
"shareAction": {
|
"shareAction": {
|
||||||
"buttonText": "Share",
|
"buttonText": "Share",
|
||||||
|
Loading…
Reference in New Issue
Block a user