mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
feat: add a loading indicator when creating, deleting, or switching workspaces. (#5067)
This commit is contained in:
parent
3e32fac876
commit
9536cde789
7
.github/workflows/ios_ci.yaml
vendored
7
.github/workflows/ios_ci.yaml
vendored
@ -86,6 +86,7 @@ jobs:
|
|||||||
model: 'iPhone 15'
|
model: 'iPhone 15'
|
||||||
shutdown_after_job: false
|
shutdown_after_job: false
|
||||||
|
|
||||||
- name: Run integration tests
|
# enable it again if the 12 mins timeout is fixed
|
||||||
working-directory: frontend/appflowy_flutter
|
# - name: Run integration tests
|
||||||
run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
|
# working-directory: frontend/appflowy_flutter
|
||||||
|
# run: flutter test integration_test/runner.dart -d ${{ steps.simulator-action.outputs.udid }}
|
||||||
|
@ -4,6 +4,7 @@ import 'dart:io';
|
|||||||
|
|
||||||
import 'package:appflowy/env/cloud_env.dart';
|
import 'package:appflowy/env/cloud_env.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
|
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
|
import 'package:appflowy/user/application/auth/af_cloud_mock_auth_service.dart';
|
||||||
@ -51,33 +52,23 @@ void main() {
|
|||||||
await tester.expectToSeeHomePageWithGetStartedPage();
|
await tester.expectToSeeHomePageWithGetStartedPage();
|
||||||
|
|
||||||
const name = 'AppFlowy.IO';
|
const name = 'AppFlowy.IO';
|
||||||
|
// the workspace will be opened after created
|
||||||
await tester.createCollaborativeWorkspace(name);
|
await tester.createCollaborativeWorkspace(name);
|
||||||
|
|
||||||
// see the success message
|
final loading = find.byType(Loading);
|
||||||
var success = find.text(LocaleKeys.workspace_createSuccess.tr());
|
await tester.pumpUntilNotFound(loading);
|
||||||
expect(success, findsOneWidget);
|
|
||||||
await tester.pumpUntilNotFound(success);
|
|
||||||
|
|
||||||
// check the create result
|
Finder success;
|
||||||
|
|
||||||
|
// delete the newly created workspace
|
||||||
await tester.openCollaborativeWorkspaceMenu();
|
await tester.openCollaborativeWorkspaceMenu();
|
||||||
var items = find.byType(WorkspaceMenuItem);
|
final Finder items = find.byType(WorkspaceMenuItem);
|
||||||
expect(items, findsNWidgets(2));
|
expect(items, findsNWidgets(2));
|
||||||
expect(
|
expect(
|
||||||
tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
|
tester.widget<WorkspaceMenuItem>(items.last).workspace.name,
|
||||||
name,
|
name,
|
||||||
);
|
);
|
||||||
|
|
||||||
// open the newly created workspace
|
|
||||||
await tester.tapButton(items.last, milliseconds: 1000);
|
|
||||||
success = find.text(LocaleKeys.workspace_openSuccess.tr());
|
|
||||||
await tester.pumpUntilFound(success);
|
|
||||||
expect(success, findsOneWidget);
|
|
||||||
await tester.pumpUntilNotFound(success);
|
|
||||||
|
|
||||||
await tester.closeCollaborativeWorkspaceMenu();
|
|
||||||
|
|
||||||
// delete the newly created workspace
|
|
||||||
await tester.openCollaborativeWorkspaceMenu();
|
|
||||||
final secondWorkspace = find.byType(WorkspaceMenuItem).last;
|
final secondWorkspace = find.byType(WorkspaceMenuItem).last;
|
||||||
await tester.hoverOnWidget(
|
await tester.hoverOnWidget(
|
||||||
secondWorkspace,
|
secondWorkspace,
|
||||||
@ -97,20 +88,11 @@ void main() {
|
|||||||
await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
|
await tester.tapButton(find.text(LocaleKeys.button_ok.tr()));
|
||||||
// delete success
|
// delete success
|
||||||
success = find.text(LocaleKeys.workspace_createSuccess.tr());
|
success = find.text(LocaleKeys.workspace_createSuccess.tr());
|
||||||
|
await tester.pumpUntilFound(success);
|
||||||
expect(success, findsOneWidget);
|
expect(success, findsOneWidget);
|
||||||
await tester.pumpUntilNotFound(success);
|
await tester.pumpUntilNotFound(success);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
// check the result
|
|
||||||
await tester.openCollaborativeWorkspaceMenu();
|
|
||||||
items = find.byType(WorkspaceMenuItem);
|
|
||||||
expect(items, findsOneWidget);
|
|
||||||
expect(
|
|
||||||
tester.widget<WorkspaceMenuItem>(items.last).workspace.name != name,
|
|
||||||
true,
|
|
||||||
);
|
|
||||||
await tester.closeCollaborativeWorkspaceMenu();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -180,7 +180,11 @@ extension AppFlowyTestBase on WidgetTester {
|
|||||||
buttons: buttons,
|
buttons: buttons,
|
||||||
warnIfMissed: warnIfMissed,
|
warnIfMissed: warnIfMissed,
|
||||||
);
|
);
|
||||||
await pumpAndSettle(Duration(milliseconds: milliseconds));
|
await pumpAndSettle(
|
||||||
|
Duration(milliseconds: milliseconds),
|
||||||
|
EnginePhase.sendSemanticsUpdate,
|
||||||
|
const Duration(seconds: 5),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> tapButtonWithName(
|
Future<void> tapButtonWithName(
|
||||||
|
@ -528,7 +528,7 @@ extension CommonOperations on WidgetTester {
|
|||||||
final workspace = find.byType(SidebarWorkspace);
|
final workspace = find.byType(SidebarWorkspace);
|
||||||
expect(workspace, findsOneWidget);
|
expect(workspace, findsOneWidget);
|
||||||
// click it
|
// click it
|
||||||
await tapButton(workspace);
|
await tapButton(workspace, milliseconds: 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> closeCollaborativeWorkspaceMenu() async {
|
Future<void> closeCollaborativeWorkspaceMenu() async {
|
||||||
@ -560,7 +560,6 @@ extension CommonOperations on WidgetTester {
|
|||||||
|
|
||||||
// input the workspace name
|
// input the workspace name
|
||||||
await enterText(find.byType(TextField), name);
|
await enterText(find.byType(TextField), name);
|
||||||
await pumpAndSettle();
|
|
||||||
|
|
||||||
await tapButtonWithName(LocaleKeys.button_ok.tr());
|
await tapButtonWithName(LocaleKeys.button_ok.tr());
|
||||||
}
|
}
|
||||||
|
@ -69,7 +69,7 @@ class MobileFolders extends StatelessWidget {
|
|||||||
...isCollaborativeWorkspace
|
...isCollaborativeWorkspace
|
||||||
? [
|
? [
|
||||||
MobileSectionFolder(
|
MobileSectionFolder(
|
||||||
title: LocaleKeys.sideBar_public.tr(),
|
title: LocaleKeys.sideBar_workspace.tr(),
|
||||||
categoryType: FolderCategoryType.public,
|
categoryType: FolderCategoryType.public,
|
||||||
views: state.section.publicViews,
|
views: state.section.publicViews,
|
||||||
),
|
),
|
||||||
|
@ -31,6 +31,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
|
|||||||
final workspace = workspaces[i];
|
final workspace = workspaces[i];
|
||||||
children.add(
|
children.add(
|
||||||
_WorkspaceMenuItem(
|
_WorkspaceMenuItem(
|
||||||
|
key: ValueKey(workspace.workspaceId),
|
||||||
userProfile: userProfile,
|
userProfile: userProfile,
|
||||||
workspace: workspace,
|
workspace: workspace,
|
||||||
showTopBorder: i == 0,
|
showTopBorder: i == 0,
|
||||||
@ -47,6 +48,7 @@ class MobileWorkspaceMenu extends StatelessWidget {
|
|||||||
|
|
||||||
class _WorkspaceMenuItem extends StatelessWidget {
|
class _WorkspaceMenuItem extends StatelessWidget {
|
||||||
const _WorkspaceMenuItem({
|
const _WorkspaceMenuItem({
|
||||||
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
required this.workspace,
|
required this.workspace,
|
||||||
required this.showTopBorder,
|
required this.showTopBorder,
|
||||||
|
@ -30,9 +30,9 @@ class DatabaseSyncBloc extends Bloc<DatabaseSyncEvent, DatabaseSyncBlocState> {
|
|||||||
.then((value) => value.fold((s) => s, (f) => null));
|
.then((value) => value.fold((s) => s, (f) => null));
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
shouldShowIndicator:
|
shouldShowIndicator: userProfile?.authenticator ==
|
||||||
userProfile?.authenticator != AuthenticatorPB.Local &&
|
AuthenticatorPB.AppFlowyCloud &&
|
||||||
databaseId != null,
|
databaseId != null,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (databaseId != null) {
|
if (databaseId != null) {
|
||||||
|
@ -32,7 +32,7 @@ class DocumentCollaboratorsBloc
|
|||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
shouldShowIndicator:
|
shouldShowIndicator:
|
||||||
userProfile?.authenticator != AuthenticatorPB.Local,
|
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
final deviceId = ApplicationInfo.deviceId;
|
final deviceId = ApplicationInfo.deviceId;
|
||||||
|
@ -31,7 +31,7 @@ class DocumentSyncBloc extends Bloc<DocumentSyncEvent, DocumentSyncBlocState> {
|
|||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
shouldShowIndicator:
|
shouldShowIndicator:
|
||||||
userProfile?.authenticator != AuthenticatorPB.Local,
|
userProfile?.authenticator == AuthenticatorPB.AppFlowyCloud,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_syncStateListener.start(
|
_syncStateListener.start(
|
||||||
|
@ -145,7 +145,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
|
|||||||
? [
|
? [
|
||||||
DocumentCollaborators(
|
DocumentCollaborators(
|
||||||
key: ValueKey('collaborators_${view.id}'),
|
key: ValueKey('collaborators_${view.id}'),
|
||||||
width: 100,
|
width: 150,
|
||||||
height: 32,
|
height: 32,
|
||||||
view: view,
|
view: view,
|
||||||
),
|
),
|
||||||
|
@ -13,6 +13,7 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
|||||||
this.borderWidth,
|
this.borderWidth,
|
||||||
this.borderColor,
|
this.borderColor,
|
||||||
this.backgroundColor,
|
this.backgroundColor,
|
||||||
|
required this.plusWidgetBuilder,
|
||||||
});
|
});
|
||||||
|
|
||||||
final List<Widget> avatars;
|
final List<Widget> avatars;
|
||||||
@ -31,13 +32,16 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
|||||||
|
|
||||||
final Color? backgroundColor;
|
final Color? backgroundColor;
|
||||||
|
|
||||||
|
final Widget Function(int value, BorderSide border) plusWidgetBuilder;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final settings = this.settings ??
|
final settings = this.settings ??
|
||||||
RestrictedPositions(
|
RestrictedPositions(
|
||||||
maxCoverage: 0.3,
|
maxCoverage: 0.3,
|
||||||
minCoverage: 0.1,
|
minCoverage: 0.2,
|
||||||
align: StackAlign.right,
|
align: StackAlign.right,
|
||||||
|
laying: StackLaying.first,
|
||||||
);
|
);
|
||||||
|
|
||||||
final border = BorderSide(
|
final border = BorderSide(
|
||||||
@ -45,27 +49,12 @@ class CollaboratorAvatarStack extends StatelessWidget {
|
|||||||
width: borderWidth ?? 2.0,
|
width: borderWidth ?? 2.0,
|
||||||
);
|
);
|
||||||
|
|
||||||
Widget textInfoWidgetBuilder(surplus) => BorderedCircleAvatar(
|
|
||||||
border: border,
|
|
||||||
backgroundColor: backgroundColor,
|
|
||||||
child: FittedBox(
|
|
||||||
child: Padding(
|
|
||||||
padding: const EdgeInsets.all(8.0),
|
|
||||||
child: Text(
|
|
||||||
'+$surplus',
|
|
||||||
style: Theme.of(context).textTheme.titleLarge,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
final infoWidgetBuilder = this.infoWidgetBuilder ?? textInfoWidgetBuilder;
|
|
||||||
|
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
height: height,
|
height: height,
|
||||||
width: width,
|
width: width,
|
||||||
child: WidgetStack(
|
child: WidgetStack(
|
||||||
positions: settings,
|
positions: settings,
|
||||||
buildInfoWidget: infoWidgetBuilder,
|
buildInfoWidget: (value) => plusWidgetBuilder(value, border),
|
||||||
stackedWidgets: avatars
|
stackedWidgets: avatars
|
||||||
.map(
|
.map(
|
||||||
(avatar) => CircleAvatar(
|
(avatar) => CircleAvatar(
|
||||||
|
@ -2,6 +2,7 @@ import 'package:appflowy/plugins/document/application/doc_collaborators_bloc.dar
|
|||||||
import 'package:appflowy/plugins/document/presentation/collaborator_avater_stack.dart';
|
import 'package:appflowy/plugins/document/presentation/collaborator_avater_stack.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||||
|
import 'package:avatar_stack/avatar_stack.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -41,8 +42,30 @@ class DocumentCollaborators extends StatelessWidget {
|
|||||||
height: height,
|
height: height,
|
||||||
width: width,
|
width: width,
|
||||||
borderWidth: 1.0,
|
borderWidth: 1.0,
|
||||||
backgroundColor:
|
plusWidgetBuilder: (value, border) {
|
||||||
Theme.of(context).colorScheme.onSecondaryContainer,
|
final lastXCollaborators = collaborators.sublist(
|
||||||
|
collaborators.length - value,
|
||||||
|
);
|
||||||
|
return BorderedCircleAvatar(
|
||||||
|
border: border,
|
||||||
|
backgroundColor: Theme.of(context).hoverColor,
|
||||||
|
child: FittedBox(
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
child: FlowyTooltip(
|
||||||
|
message: lastXCollaborators
|
||||||
|
.map((e) => e.userName)
|
||||||
|
.join('\n'),
|
||||||
|
child: FlowyText(
|
||||||
|
'+$value',
|
||||||
|
fontSize: fontSize,
|
||||||
|
color: Colors.black,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
avatars: collaborators
|
avatars: collaborators
|
||||||
.map(
|
.map(
|
||||||
(c) => FlowyTooltip(
|
(c) => FlowyTooltip(
|
||||||
|
@ -3,7 +3,7 @@ import 'package:flutter/material.dart';
|
|||||||
class Loading {
|
class Loading {
|
||||||
Loading(this.context);
|
Loading(this.context);
|
||||||
|
|
||||||
late BuildContext loadingContext;
|
BuildContext? loadingContext;
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
|
||||||
Future<void> start() async => showDialog<void>(
|
Future<void> start() async => showDialog<void>(
|
||||||
@ -24,7 +24,12 @@ class Loading {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
Future<void> stop() async => Navigator.of(loadingContext).pop();
|
Future<void> stop() async {
|
||||||
|
if (loadingContext != null) {
|
||||||
|
Navigator.of(loadingContext!).pop();
|
||||||
|
loadingContext = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class BarrierDialog {
|
class BarrierDialog {
|
||||||
|
@ -1,5 +1,9 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:appflowy/startup/plugin/plugin.dart';
|
||||||
|
import 'package:appflowy/startup/startup.dart';
|
||||||
|
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
|
||||||
|
import 'package:appflowy/workspace/application/view/view_ext.dart';
|
||||||
import 'package:appflowy/workspace/application/workspace/workspace_sections_listener.dart';
|
import 'package:appflowy/workspace/application/workspace/workspace_sections_listener.dart';
|
||||||
import 'package:appflowy/workspace/application/workspace/workspace_service.dart';
|
import 'package:appflowy/workspace/application/workspace/workspace_service.dart';
|
||||||
import 'package:appflowy_backend/log.dart';
|
import 'package:appflowy_backend/log.dart';
|
||||||
@ -152,6 +156,37 @@ class SidebarSectionsBloc
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
reload: (userProfile, workspaceId) async {
|
||||||
|
_initial(userProfile, workspaceId);
|
||||||
|
final sectionViews = await _getSectionViews();
|
||||||
|
if (sectionViews != null) {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
section: sectionViews,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
// try to open the fist view in public section or private section
|
||||||
|
if (sectionViews.publicViews.isNotEmpty) {
|
||||||
|
getIt<TabsBloc>().add(
|
||||||
|
TabsEvent.openPlugin(
|
||||||
|
plugin: sectionViews.publicViews.first.plugin(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else if (sectionViews.privateViews.isNotEmpty) {
|
||||||
|
getIt<TabsBloc>().add(
|
||||||
|
TabsEvent.openPlugin(
|
||||||
|
plugin: sectionViews.privateViews.first.plugin(),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
getIt<TabsBloc>().add(
|
||||||
|
TabsEvent.openPlugin(
|
||||||
|
plugin: makePlugin(pluginType: PluginType.blank),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -245,6 +280,10 @@ class SidebarSectionsEvent with _$SidebarSectionsEvent {
|
|||||||
const factory SidebarSectionsEvent.receiveSectionViewsUpdate(
|
const factory SidebarSectionsEvent.receiveSectionViewsUpdate(
|
||||||
SectionViewsPB sectionViews,
|
SectionViewsPB sectionViews,
|
||||||
) = _ReceiveSectionViewsUpdate;
|
) = _ReceiveSectionViewsUpdate;
|
||||||
|
const factory SidebarSectionsEvent.reload(
|
||||||
|
UserProfilePB userProfile,
|
||||||
|
String workspaceId,
|
||||||
|
) = _Reload;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -40,7 +40,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
final currentWorkspace = result.$1;
|
final currentWorkspace = result.$1;
|
||||||
final workspaces = result.$2;
|
final workspaces = result.$2;
|
||||||
final isCollabWorkspaceOn =
|
final isCollabWorkspaceOn =
|
||||||
userProfile.authenticator != AuthenticatorPB.Local &&
|
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud &&
|
||||||
FeatureFlag.collaborativeWorkspace.isOn;
|
FeatureFlag.collaborativeWorkspace.isOn;
|
||||||
if (currentWorkspace != null && result.$3 == true) {
|
if (currentWorkspace != null && result.$3 == true) {
|
||||||
final result = await _userService
|
final result = await _userService
|
||||||
@ -71,6 +71,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
);
|
);
|
||||||
},
|
},
|
||||||
createWorkspace: (name) async {
|
createWorkspace: (name) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
actionResult: const UserWorkspaceActionResult(
|
||||||
|
actionType: UserWorkspaceActionType.create,
|
||||||
|
isLoading: true,
|
||||||
|
result: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
final result = await _userService.createUserWorkspace(name);
|
final result = await _userService.createUserWorkspace(name);
|
||||||
final workspaces = result.fold(
|
final workspaces = result.fold(
|
||||||
(s) => [...state.workspaces, s],
|
(s) => [...state.workspaces, s],
|
||||||
@ -81,6 +90,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
workspaces: workspaces,
|
workspaces: workspaces,
|
||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.create,
|
actionType: UserWorkspaceActionType.create,
|
||||||
|
isLoading: false,
|
||||||
result: result,
|
result: result,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -91,6 +101,15 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
deleteWorkspace: (workspaceId) async {
|
deleteWorkspace: (workspaceId) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
actionResult: const UserWorkspaceActionResult(
|
||||||
|
actionType: UserWorkspaceActionType.delete,
|
||||||
|
isLoading: true,
|
||||||
|
result: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
final remoteWorkspaces = await _fetchWorkspaces().then(
|
final remoteWorkspaces = await _fetchWorkspaces().then(
|
||||||
(value) => value.$2,
|
(value) => value.$2,
|
||||||
);
|
);
|
||||||
@ -108,6 +127,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.delete,
|
actionType: UserWorkspaceActionType.delete,
|
||||||
result: result,
|
result: result,
|
||||||
|
isLoading: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
@ -134,11 +154,21 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.delete,
|
actionType: UserWorkspaceActionType.delete,
|
||||||
result: result,
|
result: result,
|
||||||
|
isLoading: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
openWorkspace: (workspaceId) async {
|
openWorkspace: (workspaceId) async {
|
||||||
|
emit(
|
||||||
|
state.copyWith(
|
||||||
|
actionResult: const UserWorkspaceActionResult(
|
||||||
|
actionType: UserWorkspaceActionType.open,
|
||||||
|
isLoading: true,
|
||||||
|
result: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
final result = await _userService.openWorkspace(workspaceId);
|
final result = await _userService.openWorkspace(workspaceId);
|
||||||
final currentWorkspace = result.fold(
|
final currentWorkspace = result.fold(
|
||||||
(s) => state.workspaces.firstWhereOrNull(
|
(s) => state.workspaces.firstWhereOrNull(
|
||||||
@ -157,6 +187,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
currentWorkspace: currentWorkspace,
|
currentWorkspace: currentWorkspace,
|
||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.open,
|
actionType: UserWorkspaceActionType.open,
|
||||||
|
isLoading: false,
|
||||||
result: result,
|
result: result,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -188,6 +219,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
currentWorkspace: currentWorkspace,
|
currentWorkspace: currentWorkspace,
|
||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.rename,
|
actionType: UserWorkspaceActionType.rename,
|
||||||
|
isLoading: false,
|
||||||
result: result,
|
result: result,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -221,6 +253,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
currentWorkspace: currentWorkspace,
|
currentWorkspace: currentWorkspace,
|
||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.updateIcon,
|
actionType: UserWorkspaceActionType.updateIcon,
|
||||||
|
isLoading: false,
|
||||||
result: result,
|
result: result,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -245,6 +278,7 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
workspaces: workspaces,
|
workspaces: workspaces,
|
||||||
actionResult: UserWorkspaceActionResult(
|
actionResult: UserWorkspaceActionResult(
|
||||||
actionType: UserWorkspaceActionType.leave,
|
actionType: UserWorkspaceActionType.leave,
|
||||||
|
isLoading: false,
|
||||||
result: result,
|
result: result,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -253,7 +287,11 @@ class UserWorkspaceBloc extends Bloc<UserWorkspaceEvent, UserWorkspaceState> {
|
|||||||
updateWorkspaces: (workspaces) async {
|
updateWorkspaces: (workspaces) async {
|
||||||
emit(
|
emit(
|
||||||
state.copyWith(
|
state.copyWith(
|
||||||
workspaces: workspaces.items,
|
workspaces: workspaces.items
|
||||||
|
..sort(
|
||||||
|
(a, b) =>
|
||||||
|
a.createdAtTimestamp.compareTo(b.createdAtTimestamp),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -359,11 +397,13 @@ enum UserWorkspaceActionType {
|
|||||||
class UserWorkspaceActionResult {
|
class UserWorkspaceActionResult {
|
||||||
const UserWorkspaceActionResult({
|
const UserWorkspaceActionResult({
|
||||||
required this.actionType,
|
required this.actionType,
|
||||||
|
required this.isLoading,
|
||||||
required this.result,
|
required this.result,
|
||||||
});
|
});
|
||||||
|
|
||||||
final UserWorkspaceActionType actionType;
|
final UserWorkspaceActionType actionType;
|
||||||
final FlowyResult<void, FlowyError> result;
|
final bool isLoading;
|
||||||
|
final FlowyResult<void, FlowyError>? result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
import 'package:appflowy/startup/plugin/plugin.dart';
|
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||||
import 'package:appflowy/workspace/application/favorite/prelude.dart';
|
import 'package:appflowy/workspace/application/favorite/prelude.dart';
|
||||||
@ -106,21 +105,22 @@ class HomeSideBar extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
|
BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
context.read<TabsBloc>().add(
|
final actionType = state.actionResult?.actionType;
|
||||||
TabsEvent.openPlugin(
|
|
||||||
plugin: makePlugin(pluginType: PluginType.blank),
|
if (actionType == UserWorkspaceActionType.create ||
|
||||||
),
|
actionType == UserWorkspaceActionType.delete ||
|
||||||
);
|
actionType == UserWorkspaceActionType.open) {
|
||||||
context.read<SidebarSectionsBloc>().add(
|
context.read<SidebarSectionsBloc>().add(
|
||||||
SidebarSectionsEvent.initial(
|
SidebarSectionsEvent.reload(
|
||||||
userProfile,
|
userProfile,
|
||||||
state.currentWorkspace?.workspaceId ??
|
state.currentWorkspace?.workspaceId ??
|
||||||
workspaceSetting.workspaceId,
|
workspaceSetting.workspaceId,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
context.read<FavoriteBloc>().add(
|
context.read<FavoriteBloc>().add(
|
||||||
const FavoriteEvent.fetchFavorites(),
|
const FavoriteEvent.fetchFavorites(),
|
||||||
);
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -103,10 +103,10 @@ class PublicSectionFolder extends SectionFolder {
|
|||||||
super.key,
|
super.key,
|
||||||
required super.views,
|
required super.views,
|
||||||
}) : super(
|
}) : super(
|
||||||
title: LocaleKeys.sideBar_public.tr(),
|
title: LocaleKeys.sideBar_workspace.tr(),
|
||||||
categoryType: FolderCategoryType.public,
|
categoryType: FolderCategoryType.public,
|
||||||
expandButtonTooltip: LocaleKeys.sideBar_clickToHidePublic.tr(),
|
expandButtonTooltip: LocaleKeys.sideBar_clickToHideWorkspace.tr(),
|
||||||
addButtonTooltip: LocaleKeys.sideBar_addAPageToPublic.tr(),
|
addButtonTooltip: LocaleKeys.sideBar_addAPageToWorkspace.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
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/plugins/document/presentation/editor_plugins/openai/widgets/loading.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/sidebar_setting.dart';
|
import 'package:appflowy/workspace/presentation/home/menu/sidebar/sidebar_setting.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';
|
||||||
@ -16,7 +17,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class SidebarWorkspace extends StatelessWidget {
|
class SidebarWorkspace extends StatefulWidget {
|
||||||
const SidebarWorkspace({
|
const SidebarWorkspace({
|
||||||
super.key,
|
super.key,
|
||||||
required this.userProfile,
|
required this.userProfile,
|
||||||
@ -24,6 +25,13 @@ class SidebarWorkspace extends StatelessWidget {
|
|||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<SidebarWorkspace> createState() => _SidebarWorkspaceState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _SidebarWorkspaceState extends State<SidebarWorkspace> {
|
||||||
|
Loading? loadingIndicator;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
||||||
@ -39,11 +47,11 @@ class SidebarWorkspace extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Expanded(
|
Expanded(
|
||||||
child: SidebarSwitchWorkspaceButton(
|
child: SidebarSwitchWorkspaceButton(
|
||||||
userProfile: userProfile,
|
userProfile: widget.userProfile,
|
||||||
currentWorkspace: currentWorkspace,
|
currentWorkspace: currentWorkspace,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
UserSettingButton(userProfile: userProfile),
|
UserSettingButton(userProfile: widget.userProfile),
|
||||||
const HSpace(4),
|
const HSpace(4),
|
||||||
const NotificationButton(),
|
const NotificationButton(),
|
||||||
],
|
],
|
||||||
@ -60,6 +68,19 @@ class SidebarWorkspace extends StatelessWidget {
|
|||||||
|
|
||||||
final actionType = actionResult.actionType;
|
final actionType = actionResult.actionType;
|
||||||
final result = actionResult.result;
|
final result = actionResult.result;
|
||||||
|
final isLoading = actionResult.isLoading;
|
||||||
|
|
||||||
|
if (isLoading) {
|
||||||
|
loadingIndicator ??= Loading(context)..start();
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
loadingIndicator?.stop();
|
||||||
|
loadingIndicator = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (result == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
result.onFailure((f) {
|
result.onFailure((f) {
|
||||||
Log.error(
|
Log.error(
|
||||||
@ -195,6 +216,7 @@ class _SidebarSwitchWorkspaceButtonState
|
|||||||
child: FlowyText.medium(
|
child: FlowyText.medium(
|
||||||
widget.currentWorkspace.name,
|
widget.currentWorkspace.name,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
withTooltip: true,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const FlowySvg(FlowySvgs.drop_menu_show_m),
|
const FlowySvg(FlowySvgs.drop_menu_show_m),
|
||||||
|
@ -110,7 +110,6 @@ class _WorkspaceMoreActionWrapper extends CustomActionCell {
|
|||||||
await showDialog(
|
await showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (_) => NavigatorOkCancelDialog(
|
builder: (_) => NavigatorOkCancelDialog(
|
||||||
title: LocaleKeys.workspace_leaveCurrentWorkspace.tr(),
|
|
||||||
message: LocaleKeys.workspace_leaveCurrentWorkspacePrompt.tr(),
|
message: LocaleKeys.workspace_leaveCurrentWorkspacePrompt.tr(),
|
||||||
onOkPressed: () {
|
onOkPressed: () {
|
||||||
workspaceBloc.add(
|
workspaceBloc.add(
|
||||||
|
@ -9,6 +9,7 @@ import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
|||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
@ -136,8 +137,10 @@ class WorkspaceMenuItem extends StatelessWidget {
|
|||||||
PopoverContainer.of(context).closeAll();
|
PopoverContainer.of(context).closeAll();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
margin:
|
margin: const EdgeInsets.symmetric(
|
||||||
const EdgeInsets.symmetric(vertical: 8, horizontal: 12),
|
vertical: 8,
|
||||||
|
horizontal: 12,
|
||||||
|
),
|
||||||
iconPadding: 10.0,
|
iconPadding: 10.0,
|
||||||
leftIconSize: const Size.square(32),
|
leftIconSize: const Size.square(32),
|
||||||
leftIcon: const SizedBox.square(
|
leftIcon: const SizedBox.square(
|
||||||
@ -146,12 +149,12 @@ class WorkspaceMenuItem extends StatelessWidget {
|
|||||||
rightIcon: const HSpace(42.0),
|
rightIcon: const HSpace(42.0),
|
||||||
text: Column(
|
text: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
// mainAxisAlignment: MainAxisAlignment.center,
|
|
||||||
children: [
|
children: [
|
||||||
FlowyText.medium(
|
FlowyText.medium(
|
||||||
workspace.name,
|
workspace.name,
|
||||||
fontSize: 14.0,
|
fontSize: 14.0,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
|
withTooltip: true,
|
||||||
),
|
),
|
||||||
FlowyText(
|
FlowyText(
|
||||||
state.isLoading
|
state.isLoading
|
||||||
@ -171,10 +174,14 @@ class WorkspaceMenuItem extends StatelessWidget {
|
|||||||
left: 8,
|
left: 8,
|
||||||
child: SizedBox.square(
|
child: SizedBox.square(
|
||||||
dimension: 32,
|
dimension: 32,
|
||||||
child: WorkspaceIcon(
|
child: FlowyTooltip(
|
||||||
workspace: workspace,
|
message:
|
||||||
iconSize: 26,
|
LocaleKeys.document_plugins_cover_changeIcon.tr(),
|
||||||
enableEdit: true,
|
child: WorkspaceIcon(
|
||||||
|
workspace: workspace,
|
||||||
|
iconSize: 26,
|
||||||
|
enableEdit: true,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -62,6 +62,7 @@ class SettingsDialog extends StatelessWidget {
|
|||||||
SizedBox(
|
SizedBox(
|
||||||
width: 200,
|
width: 200,
|
||||||
child: SettingsMenu(
|
child: SettingsMenu(
|
||||||
|
userProfile: user,
|
||||||
changeSelectedPage: (index) {
|
changeSelectedPage: (index) {
|
||||||
context
|
context
|
||||||
.read<SettingsDialogBloc>()
|
.read<SettingsDialogBloc>()
|
||||||
|
@ -2,6 +2,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
|||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
|
import 'package:appflowy/workspace/application/settings/settings_dialog_bloc.dart';
|
||||||
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
|
import 'package:appflowy/workspace/presentation/settings/widgets/settings_menu_element.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/foundation.dart';
|
import 'package:flutter/foundation.dart';
|
||||||
@ -12,10 +13,12 @@ class SettingsMenu extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.changeSelectedPage,
|
required this.changeSelectedPage,
|
||||||
required this.currentPage,
|
required this.currentPage,
|
||||||
|
required this.userProfile,
|
||||||
});
|
});
|
||||||
|
|
||||||
final Function changeSelectedPage;
|
final Function changeSelectedPage;
|
||||||
final SettingsPage currentPage;
|
final SettingsPage currentPage;
|
||||||
|
final UserProfilePB userProfile;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -72,7 +75,8 @@ class SettingsMenu extends StatelessWidget {
|
|||||||
icon: Icons.cut,
|
icon: Icons.cut,
|
||||||
changeSelectedPage: changeSelectedPage,
|
changeSelectedPage: changeSelectedPage,
|
||||||
),
|
),
|
||||||
if (FeatureFlag.membersSettings.isOn)
|
if (FeatureFlag.membersSettings.isOn &&
|
||||||
|
userProfile.authenticator == AuthenticatorPB.AppFlowyCloud)
|
||||||
SettingsMenuElement(
|
SettingsMenuElement(
|
||||||
page: SettingsPage.member,
|
page: SettingsPage.member,
|
||||||
selectedPage: currentPage,
|
selectedPage: currentPage,
|
||||||
|
@ -15,6 +15,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
final String? fontFamily;
|
final String? fontFamily;
|
||||||
final List<String>? fallbackFontFamily;
|
final List<String>? fallbackFontFamily;
|
||||||
final double? lineHeight;
|
final double? lineHeight;
|
||||||
|
final bool withTooltip;
|
||||||
|
|
||||||
const FlowyText(
|
const FlowyText(
|
||||||
this.text, {
|
this.text, {
|
||||||
@ -30,6 +31,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.fontFamily,
|
this.fontFamily,
|
||||||
this.fallbackFontFamily,
|
this.fallbackFontFamily,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
FlowyText.small(
|
FlowyText.small(
|
||||||
@ -44,6 +46,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.fontFamily,
|
this.fontFamily,
|
||||||
this.fallbackFontFamily,
|
this.fallbackFontFamily,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
}) : fontWeight = FontWeight.w400,
|
}) : fontWeight = FontWeight.w400,
|
||||||
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12;
|
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12;
|
||||||
|
|
||||||
@ -60,6 +63,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.fontFamily,
|
this.fontFamily,
|
||||||
this.fallbackFontFamily,
|
this.fallbackFontFamily,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
}) : fontWeight = FontWeight.w400;
|
}) : fontWeight = FontWeight.w400;
|
||||||
|
|
||||||
const FlowyText.medium(
|
const FlowyText.medium(
|
||||||
@ -75,6 +79,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.fontFamily,
|
this.fontFamily,
|
||||||
this.fallbackFontFamily,
|
this.fallbackFontFamily,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
}) : fontWeight = FontWeight.w500;
|
}) : fontWeight = FontWeight.w500;
|
||||||
|
|
||||||
const FlowyText.semibold(
|
const FlowyText.semibold(
|
||||||
@ -90,6 +95,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.fontFamily,
|
this.fontFamily,
|
||||||
this.fallbackFontFamily,
|
this.fallbackFontFamily,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
}) : fontWeight = FontWeight.w600;
|
}) : fontWeight = FontWeight.w600;
|
||||||
|
|
||||||
// Some emojis are not supported on Linux and Android, fallback to noto color emoji
|
// Some emojis are not supported on Linux and Android, fallback to noto color emoji
|
||||||
@ -104,14 +110,17 @@ class FlowyText extends StatelessWidget {
|
|||||||
this.decoration,
|
this.decoration,
|
||||||
this.selectable = false,
|
this.selectable = false,
|
||||||
this.lineHeight,
|
this.lineHeight,
|
||||||
|
this.withTooltip = false,
|
||||||
}) : fontWeight = FontWeight.w400,
|
}) : fontWeight = FontWeight.w400,
|
||||||
fontFamily = 'noto color emoji',
|
fontFamily = 'noto color emoji',
|
||||||
fallbackFontFamily = null;
|
fallbackFontFamily = null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
Widget child;
|
||||||
|
|
||||||
if (selectable) {
|
if (selectable) {
|
||||||
return SelectableText(
|
child = SelectableText(
|
||||||
text,
|
text,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
@ -126,7 +135,7 @@ class FlowyText extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
return Text(
|
child = Text(
|
||||||
text,
|
text,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
textAlign: textAlign,
|
textAlign: textAlign,
|
||||||
@ -142,5 +151,14 @@ class FlowyText extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (withTooltip) {
|
||||||
|
child = Tooltip(
|
||||||
|
message: text,
|
||||||
|
child: child,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -213,15 +213,15 @@
|
|||||||
"openSidebar": "Open side bar",
|
"openSidebar": "Open side bar",
|
||||||
"personal": "Personal",
|
"personal": "Personal",
|
||||||
"private": "Private",
|
"private": "Private",
|
||||||
"public": "Public",
|
"workspace": "Workspace",
|
||||||
"favorites": "Favorites",
|
"favorites": "Favorites",
|
||||||
"clickToHidePrivate": "Click to hide private space\nPages you created here are only visible to you",
|
"clickToHidePrivate": "Click to hide private space\nPages you created here are only visible to you",
|
||||||
"clickToHidePublic": "Click to hide public space\nPages you created here are visible to every member",
|
"clickToHideWorkspace": "Click to hide workspace\nPages you created here are visible to every member",
|
||||||
"clickToHidePersonal": "Click to hide personal space",
|
"clickToHidePersonal": "Click to hide personal space",
|
||||||
"clickToHideFavorites": "Click to hide favorite space",
|
"clickToHideFavorites": "Click to hide favorite space",
|
||||||
"addAPage": "Add a page",
|
"addAPage": "Add a page",
|
||||||
"addAPageToPrivate": "Add a page to private space",
|
"addAPageToPrivate": "Add a page to private space",
|
||||||
"addAPageToPublic": "Add a page to public space",
|
"addAPageToWorkspace": "Add a page to workspace",
|
||||||
"recent": "Recent"
|
"recent": "Recent"
|
||||||
},
|
},
|
||||||
"notifications": {
|
"notifications": {
|
||||||
|
@ -508,16 +508,14 @@ impl FolderManager {
|
|||||||
let view_id = view_id.to_string();
|
let view_id = view_id.to_string();
|
||||||
let folder = self.mutex_folder.lock();
|
let folder = self.mutex_folder.lock();
|
||||||
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
let folder = folder.as_ref().ok_or_else(folder_not_init_error)?;
|
||||||
let trash_ids = folder
|
|
||||||
.get_all_trash_sections()
|
|
||||||
.into_iter()
|
|
||||||
.map(|trash| trash.id)
|
|
||||||
.collect::<Vec<String>>();
|
|
||||||
|
|
||||||
if trash_ids.contains(&view_id) {
|
// trash views and other private views should not be accessed
|
||||||
|
let view_ids_should_be_filtered = self.get_view_ids_should_be_filtered(folder);
|
||||||
|
|
||||||
|
if view_ids_should_be_filtered.contains(&view_id) {
|
||||||
return Err(FlowyError::new(
|
return Err(FlowyError::new(
|
||||||
ErrorCode::RecordNotFound,
|
ErrorCode::RecordNotFound,
|
||||||
format!("View:{} is in trash", view_id),
|
format!("View:{} is in trash or other private section", view_id),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -531,7 +529,7 @@ impl FolderManager {
|
|||||||
.views
|
.views
|
||||||
.get_views_belong_to(&view.id)
|
.get_views_belong_to(&view.id)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter(|view| !trash_ids.contains(&view.id))
|
.filter(|view| !view_ids_should_be_filtered.contains(&view.id))
|
||||||
.collect::<Vec<_>>();
|
.collect::<Vec<_>>();
|
||||||
let view_pb = view_pb_with_child_views(view, child_views);
|
let view_pb = view_pb_with_child_views(view, child_views);
|
||||||
Ok(view_pb)
|
Ok(view_pb)
|
||||||
|
Loading…
Reference in New Issue
Block a user