chore: optimize row card page UI (#5995)

* chore: adjust buttons padding in row record page

* fix: disable more button in row page

* fix: upload image button ui on mobile

* fix: embed link button ui on mobile

* fix: add missing border for ai text field and ai translate field

* fix: delete AI can make mistakes on mobile

* chore: disable sentry

* fix: invite error toast

* fix: add member limit hint text in invite member screen

* feat: show toast after opening workspace on mobile

* chore: remove sentry

* chore: filter row page in recent views

* feat: support display field name as row page title

* chore: remove scroll bar on home page

* chore: remove legacy code

* chore: optimize mobile speed

* Revert "chore: remove sentry"

This reverts commit 73b45e2590.

* fix: reduce document page rebuild time

* chore: improve tooltip style
This commit is contained in:
Lucas.Xu 2024-08-19 11:06:34 +08:00 committed by GitHub
parent e460120a1c
commit 7113269802
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
38 changed files with 619 additions and 295 deletions

View File

@ -18,14 +18,25 @@ extension MobileRouter on BuildContext {
ViewPB view, {
Map<String, dynamic>? arguments,
bool addInRecent = true,
bool showMoreButton = true,
String? fixedTitle,
}) async {
// set the current view before pushing the new view
getIt<MenuSharedState>().latestOpenView = view;
unawaited(getIt<CachedRecentService>().updateRecentViews([view.id], true));
final queryParameters = view.queryParameters(arguments);
if (view.layout == ViewLayoutPB.Document) {
queryParameters[MobileDocumentScreen.viewShowMoreButton] =
showMoreButton.toString();
if (fixedTitle != null) {
queryParameters[MobileDocumentScreen.viewFixedTitle] = fixedTitle;
}
}
final uri = Uri(
path: view.routeName,
queryParameters: view.queryParameters(arguments),
queryParameters: queryParameters,
).toString();
await push(uri);
}

View File

@ -1,7 +1,5 @@
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/plugins/document/application/document_data_pb_extension.dart';
import 'package:appflowy/plugins/document/application/document_listener.dart';
import 'package:appflowy/plugins/document/application/document_service.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
@ -113,7 +111,6 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
);
}
final _service = DocumentService();
final ViewPB view;
final DocumentListener _documentListener;
final ViewListener _viewListener;
@ -124,16 +121,6 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
// for the version under 0.5.5
Future<(CoverType, String?)> getCoverV1() async {
final result = await _service.getDocument(documentId: view.id);
final document = result.fold((s) => s.toDocument(), (f) => null);
if (document != null) {
final coverType = CoverType.fromString(
document.root.attributes[DocumentHeaderBlockKeys.coverType],
);
final coverValue = document
.root.attributes[DocumentHeaderBlockKeys.coverDetails] as String?;
return (coverType, coverValue);
}
return (CoverType.none, null);
}

View File

@ -3,6 +3,7 @@ import 'package:appflowy/mobile/application/base/mobile_view_page_bloc.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/mobile/presentation/base/app_bar/app_bar.dart';
import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
import 'package:appflowy/shared/feature_flags.dart';
@ -26,6 +27,8 @@ class MobileViewPage extends StatefulWidget {
required this.viewLayout,
this.title,
this.arguments,
this.fixedTitle,
this.showMoreButton = true,
});
/// view id
@ -33,6 +36,10 @@ class MobileViewPage extends StatefulWidget {
final ViewLayoutPB viewLayout;
final String? title;
final Map<String, dynamic>? arguments;
final bool showMoreButton;
// only used in row page
final String? fixedTitle;
@override
State<MobileViewPage> createState() => _MobileViewPageState();
@ -163,6 +170,9 @@ class _MobileViewPageState extends State<MobileViewPage> {
return plugin.widgetBuilder.buildWidget(
shrinkWrap: false,
context: PluginContext(userProfile: state.userProfilePB),
data: {
MobileDocumentScreen.viewFixedTitle: widget.fixedTitle,
},
);
},
(error) {
@ -215,13 +225,19 @@ class _MobileViewPageState extends State<MobileViewPage> {
]);
}
actions.addAll([
MobileViewPageMoreButton(
view: view,
isImmersiveMode: isImmersiveMode,
appBarOpacity: _appBarOpacity,
),
]);
if (widget.showMoreButton) {
actions.addAll([
MobileViewPageMoreButton(
view: view,
isImmersiveMode: isImmersiveMode,
appBarOpacity: _appBarOpacity,
),
]);
} else {
actions.addAll([
const HSpace(18.0),
]);
}
return actions;
}
@ -241,7 +257,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
],
Expanded(
child: FlowyText.medium(
view?.name ?? widget.title ?? '',
widget.fixedTitle ?? view?.name ?? widget.title ?? '',
fontSize: 15.0,
overflow: TextOverflow.ellipsis,
figmaLineHeight: 18.0,

View File

@ -295,6 +295,7 @@ class MobileRowDetailPageContentState
RowCache get rowCache => widget.databaseController.rowCache;
FieldController get fieldController =>
widget.databaseController.fieldController;
ValueNotifier<String> primaryFieldId = ValueNotifier('');
@override
void initState() {
@ -327,7 +328,13 @@ class MobileRowDetailPageContentState
fieldController: fieldController,
rowMeta: rowController.rowMeta,
)..add(const RowBannerEvent.initial()),
child: BlocBuilder<RowBannerBloc, RowBannerState>(
child: BlocConsumer<RowBannerBloc, RowBannerState>(
listener: (context, state) {
if (state.primaryField == null) {
return;
}
primaryFieldId.value = state.primaryField!.id;
},
builder: (context, state) {
if (state.primaryField == null) {
return const SizedBox.shrink();
@ -367,8 +374,22 @@ class MobileRowDetailPageContentState
if (rowDetailState.numHiddenFields != 0) ...[
const ToggleHiddenFieldsVisibilityButton(),
],
OpenRowPageButton(
documentId: rowController.rowMeta.documentId,
const VSpace(8.0),
ValueListenableBuilder(
valueListenable: primaryFieldId,
builder: (context, primaryFieldId, child) {
if (primaryFieldId.isEmpty) {
return const SizedBox.shrink();
}
return OpenRowPageButton(
databaseController: widget.databaseController,
cellContext: CellContext(
rowId: rowController.rowId,
fieldId: primaryFieldId,
),
documentId: rowController.rowMeta.documentId,
);
},
),
MobileRowDetailCreateFieldButton(
viewId: viewId,

View File

@ -22,7 +22,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
minHeight: GridSize.headerHeight,
maxHeight: GridSize.headerHeight,
),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
@ -37,7 +37,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
EdgeInsets.symmetric(horizontal: 6, vertical: 2),
),
),
label: FlowyText.medium(

View File

@ -3,6 +3,10 @@ import 'dart:async';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/plugins/database/application/cell/bloc/text_cell_bloc.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/workspace/application/view/prelude.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
@ -11,20 +15,33 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
class OpenRowPageButton extends StatefulWidget {
const OpenRowPageButton({
super.key,
required this.documentId,
required this.databaseController,
required this.cellContext,
});
final String documentId;
final DatabaseController databaseController;
final CellContext cellContext;
@override
State<OpenRowPageButton> createState() => _OpenRowPageButtonState();
}
class _OpenRowPageButtonState extends State<OpenRowPageButton> {
late final cellBloc = TextCellBloc(
cellController: makeCellController(
widget.databaseController,
widget.cellContext,
).as(),
);
ViewPB? view;
@override
@ -36,44 +53,52 @@ class _OpenRowPageButtonState extends State<OpenRowPageButton> {
@override
Widget build(BuildContext context) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
minHeight: GridSize.headerHeight,
),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
return BlocBuilder<TextCellBloc, TextCellState>(
bloc: cellBloc,
builder: (context, state) {
return ConstrainedBox(
constraints: BoxConstraints(
minWidth: double.infinity,
maxHeight: GridSize.buttonHeight,
),
child: TextButton.icon(
style: Theme.of(context).textButtonTheme.style?.copyWith(
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(12.0),
),
),
overlayColor: WidgetStateProperty.all<Color>(
Theme.of(context).hoverColor,
),
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(horizontal: 6),
),
),
),
overlayColor: WidgetStateProperty.all<Color>(
Theme.of(context).hoverColor,
),
alignment: AlignmentDirectional.centerStart,
splashFactory: NoSplash.splashFactory,
padding: const WidgetStatePropertyAll(
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
label: FlowyText.medium(
LocaleKeys.grid_field_openRowDocument.tr(),
fontSize: 15,
),
icon: const Padding(
padding: EdgeInsets.all(4.0),
child: FlowySvg(
FlowySvgs.full_view_s,
size: Size.square(16.0),
),
),
label: FlowyText.medium(
LocaleKeys.grid_field_openRowDocument.tr(),
fontSize: 15,
),
icon: const Padding(
padding: EdgeInsets.all(4.0),
child: FlowySvg(
FlowySvgs.full_view_s,
size: Size.square(16.0),
onPressed: () {
final name = state.content;
_openRowPage(context, name);
},
),
),
onPressed: () => _openRowPage(context),
),
);
},
);
}
Future<void> _openRowPage(BuildContext context) async {
Future<void> _openRowPage(BuildContext context, String fieldName) async {
Log.info('Open row page(${widget.documentId})');
if (view == null) {
@ -89,6 +114,8 @@ class _OpenRowPageButtonState extends State<OpenRowPageButton> {
await context.pushView(
view!,
addInRecent: false,
showMoreButton: false,
fixedTitle: fieldName,
);
}
}

View File

@ -7,15 +7,21 @@ class MobileDocumentScreen extends StatelessWidget {
super.key,
required this.id,
this.title,
this.showMoreButton = true,
this.fixedTitle,
});
/// view id
final String id;
final String? title;
final bool showMoreButton;
final String? fixedTitle;
static const routeName = '/docs';
static const viewId = 'id';
static const viewTitle = 'title';
static const viewShowMoreButton = 'show_more_button';
static const viewFixedTitle = 'fixed_title';
@override
Widget build(BuildContext context) {
@ -23,6 +29,8 @@ class MobileDocumentScreen extends StatelessWidget {
id: id,
title: title,
viewLayout: ViewLayoutPB.Document,
showMoreButton: showMoreButton,
fixedTitle: fixedTitle,
);
}
}

View File

@ -96,36 +96,34 @@ class _FavoriteViews extends StatelessWidget {
final borderColor = Theme.of(context).isLightMode
? const Color(0xFFE9E9EC)
: const Color(0x1AFFFFFF);
return Scrollbar(
child: ListView.separated(
key: const PageStorageKey('favorite_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final view = favoriteViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
return ListView.separated(
key: const PageStorageKey('favorite_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final view = favoriteViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
),
child: MobileViewPage(
key: ValueKey(view.item.id),
view: view.item,
timestamp: view.timestamp,
type: MobilePageCardType.favorite,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: favoriteViews.length,
),
),
child: MobileViewPage(
key: ValueKey(view.item.id),
view: view.item,
timestamp: view.timestamp,
type: MobilePageCardType.favorite,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: favoriteViews.length,
);
}
}

View File

@ -25,19 +25,17 @@ class _MobileHomeSpaceState extends State<MobileHomeSpace>
final workspaceId =
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return Scrollbar(
child: SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
top: HomeSpaceViewSizes.mVerticalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
child: MobileFolders(
user: widget.userProfile,
workspaceId: workspaceId,
showFavorite: false,
),
return SingleChildScrollView(
child: Padding(
padding: EdgeInsets.only(
top: HomeSpaceViewSizes.mVerticalPadding,
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
child: MobileFolders(
user: widget.userProfile,
workspaceId: workspaceId,
showFavorite: false,
),
),
);

View File

@ -35,6 +35,9 @@ class MobileFolders extends StatelessWidget {
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
'';
return BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
listenWhen: (previous, current) =>
previous.currentWorkspace?.workspaceId !=
current.currentWorkspace?.workspaceId,
listener: (context, state) {
context.read<SidebarSectionsBloc>().add(
SidebarSectionsEvent.initial(

View File

@ -1,8 +1,10 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/home/mobile_home_page_header.dart';
import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.dart';
import 'package:appflowy/mobile/presentation/home/tab/space_order_bloc.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/widgets/loading.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
@ -14,15 +16,19 @@ import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
import 'package:appflowy/workspace/presentation/home/errors/workspace_failed_screen.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/menu/menu_shared_state.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:appflowy_backend/dispatch/dispatch.dart';
import 'package:appflowy_backend/log.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';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
import 'package:sentry/sentry.dart';
import 'package:toastification/toastification.dart';
class MobileHomeScreen extends StatelessWidget {
const MobileHomeScreen({super.key});
@ -103,6 +109,8 @@ class MobileHomePage extends StatefulWidget {
}
class _MobileHomePageState extends State<MobileHomePage> {
Loading? loadingIndicator;
@override
void initState() {
super.initState();
@ -147,11 +155,18 @@ class _MobileHomePageState extends State<MobileHomePage> {
}
}
class _HomePage extends StatelessWidget {
class _HomePage extends StatefulWidget {
const _HomePage({required this.userProfile});
final UserProfilePB userProfile;
@override
State<_HomePage> createState() => _HomePageState();
}
class _HomePageState extends State<_HomePage> {
Loading? loadingIndicator;
@override
Widget build(BuildContext context) {
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
@ -161,6 +176,8 @@ class _HomePage extends StatelessWidget {
listener: (context, state) {
getIt<CachedRecentService>().reset();
mCurrentWorkspace.value = state.currentWorkspace;
_showResultDialog(context, state);
},
builder: (context, state) {
if (state.currentWorkspace == null) {
@ -170,6 +187,7 @@ class _HomePage extends StatelessWidget {
final workspaceId = state.currentWorkspace!.workspaceId;
return Column(
key: ValueKey('mobile_home_page_$workspaceId'),
children: [
// Header
Padding(
@ -179,7 +197,7 @@ class _HomePage extends StatelessWidget {
top: Platform.isAndroid ? 8.0 : 0.0,
),
child: MobileHomePageHeader(
userProfile: userProfile,
userProfile: widget.userProfile,
),
),
@ -194,7 +212,7 @@ class _HomePage extends StatelessWidget {
create: (_) => SidebarSectionsBloc()
..add(
SidebarSectionsEvent.initial(
userProfile,
widget.userProfile,
workspaceId,
),
),
@ -207,7 +225,7 @@ class _HomePage extends StatelessWidget {
create: (_) => SpaceBloc()
..add(
SpaceEvent.initial(
userProfile,
widget.userProfile,
workspaceId,
openFirstPage: false,
),
@ -215,7 +233,7 @@ class _HomePage extends StatelessWidget {
),
],
child: MobileSpaceTab(
userProfile: userProfile,
userProfile: widget.userProfile,
),
),
),
@ -224,4 +242,59 @@ class _HomePage extends StatelessWidget {
},
);
}
void _showResultDialog(BuildContext context, UserWorkspaceState state) {
final actionResult = state.actionResult;
if (actionResult == null) {
return;
}
final actionType = actionResult.actionType;
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) {
Log.error(
'[Workspace] Failed to perform ${actionType.toString()} action: $f',
);
});
final String? message;
ToastificationType toastType = ToastificationType.success;
switch (actionType) {
case UserWorkspaceActionType.open:
message = result.fold(
(s) {
toastType = ToastificationType.success;
return LocaleKeys.workspace_openSuccess.tr();
},
(e) {
toastType = ToastificationType.error;
return '${LocaleKeys.workspace_openFailed.tr()}: ${e.msg}';
},
);
break;
default:
message = null;
toastType = ToastificationType.error;
break;
}
if (message != null) {
showToastNotification(context, message: message, type: toastType);
}
}
}

View File

@ -68,36 +68,34 @@ class _RecentViews extends StatelessWidget {
? const Color(0xFFE9E9EC)
: const Color(0x1AFFFFFF);
return SlidableAutoCloseBehavior(
child: Scrollbar(
child: ListView.separated(
key: const PageStorageKey('recent_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final sectionView = recentViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
child: ListView.separated(
key: const PageStorageKey('recent_views_page_storage_key'),
padding: EdgeInsets.only(
bottom: HomeSpaceViewSizes.mVerticalPadding +
MediaQuery.of(context).padding.bottom,
),
itemBuilder: (context, index) {
final sectionView = recentViews[index];
return Container(
padding: const EdgeInsets.symmetric(vertical: 24.0),
decoration: BoxDecoration(
border: Border(
bottom: BorderSide(
color: borderColor,
width: 0.5,
),
),
child: MobileViewPage(
key: ValueKey(sectionView.item.id),
view: sectionView.item,
timestamp: sectionView.timestamp,
type: MobilePageCardType.recent,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: recentViews.length,
),
),
child: MobileViewPage(
key: ValueKey(sectionView.item.id),
view: sectionView.item,
timestamp: sectionView.timestamp,
type: MobilePageCardType.recent,
),
);
},
separatorBuilder: (context, index) => const HSpace(8),
itemCount: recentViews.length,
),
);
}

View File

@ -7,7 +7,8 @@ import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/shared/appflowy_cache_manager.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/util/share_log_files.dart';
import 'package:appflowy/workspace/presentation/home/toast.dart';
import 'package:appflowy/workspace/presentation/settings/pages/fix_data_widget.dart';
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@ -74,10 +75,14 @@ class SupportSettingGroup extends StatelessWidget {
actionButtonTitle: LocaleKeys.button_yes.tr(),
onActionButtonPressed: () async {
await getIt<FlowyCacheManager>().clearAllCache();
// check the workspace and space health
await WorkspaceDataManager.checkViewHealth(
dryRun: false,
);
if (context.mounted) {
showSnackBarMessage(
showToastNotification(
context,
LocaleKeys.settings_files_clearCacheSuccess.tr(),
message: LocaleKeys.settings_files_clearCacheSuccess.tr(),
);
}
},

View File

@ -48,6 +48,7 @@ class _InviteMemberPage extends StatefulWidget {
class _InviteMemberPageState extends State<_InviteMemberPage> {
final emailController = TextEditingController();
late final Future<UserProfilePB?> userProfile;
bool exceededLimit = false;
@override
void initState() {
@ -131,6 +132,15 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
),
),
const VSpace(16),
if (exceededLimit) ...[
FlowyText.regular(
LocaleKeys.settings_appearance_members_inviteFailedMemberLimit.tr(),
fontSize: 14.0,
maxLines: 3,
color: Theme.of(context).colorScheme.error,
),
const VSpace(16),
],
SizedBox(
width: double.infinity,
child: ElevatedButton(
@ -197,6 +207,9 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
final message = f.code == ErrorCode.WorkspaceMemberLimitExceeded
? LocaleKeys.settings_appearance_members_memberLimitExceeded.tr()
: LocaleKeys.settings_appearance_members_failedToAddMember.tr();
setState(() {
exceededLimit = f.code == ErrorCode.WorkspaceMemberLimitExceeded;
});
showToastNotification(
context,
type: ToastificationType.error,
@ -220,6 +233,9 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
.tr()
: LocaleKeys.settings_appearance_members_failedToInviteMember
.tr();
setState(() {
exceededLimit = f.code == ErrorCode.WorkspaceMemberLimitExceeded;
});
showToastNotification(
context,
type: ToastificationType.error,
@ -255,6 +271,7 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
if (!isEmail(email)) {
return showToastNotification(
context,
type: ToastificationType.error,
message: LocaleKeys.settings_appearance_members_emailInvalidError.tr(),
);
}

View File

@ -425,13 +425,14 @@ class _ChatContentPageState extends State<_ChatContentPage> {
},
),
const VSpace(6),
Opacity(
opacity: 0.6,
child: FlowyText(
LocaleKeys.chat_aiMistakePrompt.tr(),
fontSize: 12,
if (PlatformExtension.isDesktop)
Opacity(
opacity: 0.6,
child: FlowyText(
LocaleKeys.chat_aiMistakePrompt.tr(),
fontSize: 12,
),
),
),
],
);
},

View File

@ -6,6 +6,7 @@ class GridSize {
static double get scrollBarSize => 8 * scale;
static double get headerHeight => 40 * scale;
static double get buttonHeight => 38 * scale;
static double get footerHeight => 40 * scale;
static double get horizontalHeaderPadding =>
PlatformExtension.isDesktop ? 40 * scale : 16 * scale;

View File

@ -188,8 +188,14 @@ class _RowMenuButtonState extends State<RowMenuButton> {
richTooltipText: widget.isDragEnabled
? TextSpan(
children: [
TextSpan(text: '${LocaleKeys.tooltip_dragRow.tr()}\n'),
TextSpan(text: LocaleKeys.tooltip_openMenu.tr()),
TextSpan(
text: '${LocaleKeys.tooltip_dragRow.tr()}\n',
style: context.tooltipTextStyle(),
),
TextSpan(
text: LocaleKeys.tooltip_openMenu.tr(),
style: context.tooltipTextStyle(),
),
],
)
: null,

View File

@ -13,42 +13,54 @@ class MobileRowDetailSummaryCellSkin extends IEditableSummaryCellSkin {
FocusNode focusNode,
TextEditingController textEditingController,
) {
return Column(
children: [
TextField(
controller: textEditingController,
readOnly: true,
focusNode: focusNode,
onEditingComplete: () => focusNode.unfocus(),
onSubmitted: (_) => focusNode.unfocus(),
style: Theme.of(context).textTheme.bodyMedium,
textInputAction: TextInputAction.done,
maxLines: null,
minLines: 1,
decoration: InputDecoration(
contentPadding: GridSize.cellContentInsets,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
isDense: true,
),
return Container(
decoration: BoxDecoration(
border: Border.fromBorderSide(
BorderSide(color: Theme.of(context).colorScheme.outline),
),
Row(
children: [
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: SummaryCellAccessory(
viewId: bloc.cellController.viewId,
fieldId: bloc.cellController.fieldId,
rowId: bloc.cellController.rowId,
),
borderRadius: const BorderRadius.all(Radius.circular(14)),
),
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 2,
),
child: Column(
children: [
TextField(
controller: textEditingController,
readOnly: true,
focusNode: focusNode,
onEditingComplete: () => focusNode.unfocus(),
onSubmitted: (_) => focusNode.unfocus(),
style: Theme.of(context).textTheme.bodyMedium,
textInputAction: TextInputAction.done,
maxLines: null,
minLines: 1,
decoration: InputDecoration(
contentPadding: GridSize.cellContentInsets,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
isDense: true,
),
],
),
],
),
Row(
children: [
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: SummaryCellAccessory(
viewId: bloc.cellController.viewId,
fieldId: bloc.cellController.fieldId,
rowId: bloc.cellController.rowId,
),
),
],
),
],
),
);
}
}

View File

@ -13,42 +13,54 @@ class MobileRowDetailTranslateCellSkin extends IEditableTranslateCellSkin {
FocusNode focusNode,
TextEditingController textEditingController,
) {
return Column(
children: [
TextField(
readOnly: true,
controller: textEditingController,
focusNode: focusNode,
onEditingComplete: () => focusNode.unfocus(),
onSubmitted: (_) => focusNode.unfocus(),
style: Theme.of(context).textTheme.bodyMedium,
textInputAction: TextInputAction.done,
maxLines: null,
minLines: 1,
decoration: InputDecoration(
contentPadding: GridSize.cellContentInsets,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
isDense: true,
),
return Container(
decoration: BoxDecoration(
border: Border.fromBorderSide(
BorderSide(color: Theme.of(context).colorScheme.outline),
),
Row(
children: [
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: TranslateCellAccessory(
viewId: bloc.cellController.viewId,
fieldId: bloc.cellController.fieldId,
rowId: bloc.cellController.rowId,
),
borderRadius: const BorderRadius.all(Radius.circular(14)),
),
padding: const EdgeInsets.symmetric(
horizontal: 4,
vertical: 2,
),
child: Column(
children: [
TextField(
readOnly: true,
controller: textEditingController,
focusNode: focusNode,
onEditingComplete: () => focusNode.unfocus(),
onSubmitted: (_) => focusNode.unfocus(),
style: Theme.of(context).textTheme.bodyMedium,
textInputAction: TextInputAction.done,
maxLines: null,
minLines: 1,
decoration: InputDecoration(
contentPadding: GridSize.cellContentInsets,
border: InputBorder.none,
focusedBorder: InputBorder.none,
enabledBorder: InputBorder.none,
errorBorder: InputBorder.none,
disabledBorder: InputBorder.none,
isDense: true,
),
],
),
],
),
Row(
children: [
const Spacer(),
Padding(
padding: const EdgeInsets.all(8.0),
child: TranslateCellAccessory(
viewId: bloc.cellController.viewId,
fieldId: bloc.cellController.fieldId,
rowId: bloc.cellController.rowId,
),
),
],
),
],
),
);
}
}

View File

@ -1,8 +1,5 @@
import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
@ -21,10 +18,11 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/theme_extension.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import '../cell/editable_cell_builder.dart';
import 'accessory/cell_accessory.dart';
/// Display the row properties in a list. Only used in [RowDetailPage].
@ -165,6 +163,7 @@ class _PropertyCellState extends State<_PropertyCell> {
svg: FlowySvgs.drag_element_s,
richMessage: TextSpan(
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
style: context.tooltipTextStyle(),
),
),
),

View File

@ -2,6 +2,7 @@ library document_plugin;
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
import 'package:appflowy/plugins/document/document_page.dart';
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
@ -118,6 +119,8 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
}
});
final fixedTitle = data?[MobileDocumentScreen.viewFixedTitle];
return BlocProvider<ViewInfoBloc>.value(
value: bloc,
child: BlocBuilder<DocumentAppearanceCubit, DocumentAppearance>(
@ -126,6 +129,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
view: view,
onDeleted: () => context.onDeleted?.call(view, deletedViewIndex),
initialSelection: initialSelection,
fixedTitle: fixedTitle,
),
),
);

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
import 'package:appflowy/plugins/document/application/document_bloc.dart';
@ -26,6 +24,7 @@ import 'package:cross_file/cross_file.dart';
import 'package:desktop_drop/desktop_drop.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:provider/provider.dart';
@ -42,11 +41,13 @@ class DocumentPage extends StatefulWidget {
required this.view,
required this.onDeleted,
this.initialSelection,
this.fixedTitle,
});
final ViewPB view;
final VoidCallback onDeleted;
final Selection? initialSelection;
final String? fixedTitle;
@override
State<DocumentPage> createState() => _DocumentPageState();
@ -103,6 +104,7 @@ class _DocumentPageState extends State<DocumentPage>
BlocProvider.value(value: documentBloc),
],
child: BlocBuilder<DocumentBloc, DocumentState>(
buildWhen: _shouldRebuildDocument,
builder: (context, state) {
if (state.isLoading) {
return const Center(child: CircularProgressIndicator.adaptive());
@ -261,6 +263,7 @@ class _DocumentPageState extends State<DocumentPage>
if (PlatformExtension.isMobile) {
return DocumentImmersiveCover(
fixedTitle: widget.fixedTitle,
view: widget.view,
userProfilePB: userProfilePB,
);
@ -308,4 +311,31 @@ class _DocumentPageState extends State<DocumentPage>
}
}
}
bool _shouldRebuildDocument(DocumentState previous, DocumentState current) {
// only rebuild the document page when the below fields are changed
// this is to prevent unnecessary rebuilds
//
// If you confirm the newly added fields should be rebuilt, please update
// this function.
if (previous.editorState != current.editorState) {
return true;
}
if (previous.forceClose != current.forceClose ||
previous.isDeleted != current.isDeleted) {
return true;
}
if (previous.userProfilePB != current.userProfilePB) {
return true;
}
if (previous.isLoading != current.isLoading ||
previous.error != current.error) {
return true;
}
return false;
}
}

View File

@ -5,6 +5,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/actions/block_action_button.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
@ -31,16 +32,19 @@ class BlockAddButton extends StatelessWidget {
children: [
TextSpan(
text: LocaleKeys.blockActions_addBelowTooltip.tr(),
style: context.tooltipTextStyle(),
),
const TextSpan(text: '\n'),
TextSpan(
text: Platform.isMacOS
? LocaleKeys.blockActions_addAboveMacCmd.tr()
: LocaleKeys.blockActions_addAboveCmd.tr(),
style: context.tooltipTextStyle(),
),
const TextSpan(text: ' '),
TextSpan(
text: LocaleKeys.blockActions_addAboveTooltip.tr(),
style: context.tooltipTextStyle(),
),
],
),

View File

@ -21,7 +21,6 @@ class BlockActionButton extends StatelessWidget {
Widget build(BuildContext context) {
return Align(
child: FlowyTooltip(
preferBelow: false,
richMessage: richMessage,
child: MouseRegion(
cursor: Platform.isWindows

View File

@ -7,6 +7,7 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -67,11 +68,14 @@ class BlockOptionButton extends StatelessWidget {
controller.close();
}
},
buildChild: (controller) => _buildOptionButton(controller),
buildChild: (controller) => _buildOptionButton(context, controller),
);
}
Widget _buildOptionButton(PopoverController controller) {
Widget _buildOptionButton(
BuildContext context,
PopoverController controller,
) {
return BlockActionButton(
svg: FlowySvgs.drag_element_s,
richMessage: TextSpan(
@ -79,9 +83,11 @@ class BlockOptionButton extends StatelessWidget {
TextSpan(
// todo: customize the color to highlight the text.
text: LocaleKeys.document_plugins_optionAction_click.tr(),
style: context.tooltipTextStyle(),
),
TextSpan(
text: LocaleKeys.document_plugins_optionAction_toOpenMenu.tr(),
style: context.tooltipTextStyle(),
),
],
),

View File

@ -34,10 +34,12 @@ class DocumentImmersiveCover extends StatefulWidget {
super.key,
required this.view,
required this.userProfilePB,
this.fixedTitle,
});
final ViewPB view;
final UserProfilePB userProfilePB;
final String? fixedTitle;
@override
State<DocumentImmersiveCover> createState() => _DocumentImmersiveCoverState();
@ -143,6 +145,18 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
fontFamily = getGoogleFontSafely(documentFontFamily).fontFamily;
}
if (widget.fixedTitle != null) {
return FlowyText(
widget.fixedTitle!,
fontSize: 28.0,
fontWeight: FontWeight.w700,
fontFamily: fontFamily,
color:
state.cover.isNone || state.cover.isPresets ? null : Colors.white,
overflow: TextOverflow.ellipsis,
);
}
return AutoSizeTextField(
controller: textEditingController,
focusNode: focusNode,

View File

@ -121,38 +121,36 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
final type = values[currentTabIndex];
switch (type) {
case UploadImageType.local:
return Column(
children: [
Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Theme.of(context).colorScheme.outline,
),
),
constraints: constraints,
child: Column(
children: [
UploadImageFileWidget(
allowMultipleImages: widget.allowMultipleImages,
onPickFiles: widget.onSelectedLocalImages,
),
],
Widget child = UploadImageFileWidget(
allowMultipleImages: widget.allowMultipleImages,
onPickFiles: widget.onSelectedLocalImages,
);
if (PlatformExtension.isDesktop) {
child = Padding(
padding: const EdgeInsets.all(8.0),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Theme.of(context).colorScheme.outline,
),
),
constraints: constraints,
child: child,
),
// if (widget.limitMaximumImageSize) ...[
// FlowyText(
// LocaleKeys.document_imageBlock_maximumImageSize.tr(),
// fontSize: 10.0,
// color: Theme.of(context).hintColor,
// ),
// ],
],
);
);
} else {
child = Padding(
padding: const EdgeInsets.symmetric(
horizontal: 8.0,
vertical: 12.0,
),
child: child,
);
}
return child;
case UploadImageType.url:
return Container(
padding: const EdgeInsets.all(8.0),

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/patterns/common_patterns.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
@ -22,14 +23,27 @@ class _EmbedImageUrlWidgetState extends State<EmbedImageUrlWidget> {
@override
Widget build(BuildContext context) {
final textField = FlowyTextField(
hintText: LocaleKeys.document_imageBlock_embedLink_placeholder.tr(),
onChanged: (value) => inputText = value,
onEditingComplete: submit,
textStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(
fontSize: 14,
),
hintStyle: Theme.of(context).textTheme.bodyMedium?.copyWith(
color: Theme.of(context).hintColor,
fontSize: 14,
),
);
return Column(
children: [
const VSpace(12),
FlowyTextField(
hintText: LocaleKeys.document_imageBlock_embedLink_placeholder.tr(),
onChanged: (value) => inputText = value,
onEditingComplete: submit,
),
PlatformExtension.isDesktop
? textField
: SizedBox(
height: 42,
child: textField,
),
if (!isUrlValid) ...[
const VSpace(12),
FlowyText(
@ -39,18 +53,23 @@ class _EmbedImageUrlWidgetState extends State<EmbedImageUrlWidget> {
],
const VSpace(20),
SizedBox(
height: 32,
height: PlatformExtension.isMobile ? 36 : 32,
width: 300,
child: FlowyButton(
backgroundColor: Theme.of(context).colorScheme.primary,
hoverColor: Theme.of(context).colorScheme.primary.withOpacity(0.9),
showDefaultBoxDecorationOnMobile: true,
radius:
PlatformExtension.isMobile ? BorderRadius.circular(8) : null,
margin: const EdgeInsets.all(5),
text: FlowyText(
LocaleKeys.document_imageBlock_embedLink_label.tr(),
lineHeight: 1,
textAlign: TextAlign.center,
color: Theme.of(context).colorScheme.onPrimary,
color: PlatformExtension.isMobile
? null
: Theme.of(context).colorScheme.onPrimary,
fontSize: PlatformExtension.isMobile ? 14 : null,
),
onTap: submit,
),

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/shared/permission/permission_checker.dart';
import 'package:appflowy/startup/startup.dart';
@ -9,6 +7,7 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/file_picker/file_picker_service.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:image_picker/image_picker.dart';
class UploadImageFileWidget extends StatelessWidget {
@ -25,8 +24,9 @@ class UploadImageFileWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final child = FlowyButton(
Widget child = FlowyButton(
showDefaultBoxDecorationOnMobile: true,
radius: PlatformExtension.isMobile ? BorderRadius.circular(8.0) : null,
text: Container(
margin: const EdgeInsets.all(4.0),
alignment: Alignment.center,
@ -38,7 +38,12 @@ class UploadImageFileWidget extends StatelessWidget {
);
if (PlatformExtension.isDesktopOrWeb) {
return FlowyHover(child: child);
child = FlowyHover(child: child);
} else {
child = Padding(
padding: const EdgeInsets.symmetric(horizontal: 8.0),
child: child,
);
}
return child;

View File

@ -8,12 +8,22 @@ class Loading {
BuildContext? loadingContext;
final BuildContext context;
bool hasStopped = false;
void start() => unawaited(
showDialog<void>(
context: context,
barrierDismissible: false,
builder: (BuildContext context) {
loadingContext = context;
if (hasStopped) {
WidgetsBinding.instance.addPostFrameCallback((_) {
Navigator.of(loadingContext!).pop();
loadingContext = null;
});
}
return const SimpleDialog(
elevation: 0.0,
backgroundColor:
@ -33,6 +43,8 @@ class Loading {
Navigator.of(loadingContext!).pop();
loadingContext = null;
}
hasStopped = true;
}
}

View File

@ -493,9 +493,20 @@ GoRoute _mobileEditorScreenRoute() {
pageBuilder: (context, state) {
final id = state.uri.queryParameters[MobileDocumentScreen.viewId]!;
final title = state.uri.queryParameters[MobileDocumentScreen.viewTitle];
final showMoreButton = bool.tryParse(
state.uri.queryParameters[MobileDocumentScreen.viewShowMoreButton] ??
'true',
);
final fixedTitle =
state.uri.queryParameters[MobileDocumentScreen.viewFixedTitle];
return MaterialExtendedPage(
child: MobileDocumentScreen(id: id, title: title),
child: MobileDocumentScreen(
id: id,
title: title,
showMoreButton: showMoreButton ?? true,
fixedTitle: fixedTitle,
),
);
},
);

View File

@ -33,7 +33,7 @@ class CachedRecentService {
final _listener = RecentViewsListener();
Future<List<SectionViewPB>> recentViews() async {
if (_isInitialized) return _recentViews;
if (_isInitialized || _completer.isCompleted) return _recentViews;
_isInitialized = true;
@ -76,7 +76,10 @@ class CachedRecentService {
(recentViews) {
return FlowyResult.success(
RepeatedRecentViewPB(
items: recentViews.items.where((e) => !e.item.isSpace),
// filter the space view and the orphan view
items: recentViews.items.where(
(e) => !e.item.isSpace && e.item.id != e.item.parentViewId,
),
),
);
},

View File

@ -68,6 +68,8 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
(event, emit) async {
await event.when(
initial: (userProfile, workspaceId, openFirstPage) async {
this.openFirstPage = openFirstPage;
_initial(userProfile, workspaceId);
final (spaces, publicViews, privateViews) = await _getSpaces();
@ -305,7 +307,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
SpaceEvent.initial(
userProfile,
workspaceId,
openFirstPage: true,
openFirstPage: openFirstPage,
),
);
},
@ -353,6 +355,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
String? _workspaceId;
late UserProfilePB userProfile;
WorkspaceSectionsListener? _listener;
bool openFirstPage = false;
@override
Future<void> close() async {

View File

@ -118,6 +118,8 @@ class WorkspaceDataManager {
final List<ViewPB> unlistedChildViews = [];
// Views whose parent is not in allViews
final List<ViewPB> orphanViews = [];
// Row pages
final List<ViewPB> rowPageViews = [];
try {
if (workspace == null || allViews == null) {
@ -145,6 +147,11 @@ class WorkspaceDataManager {
continue;
}
if (parentView.id == view.id) {
rowPageViews.add(view);
continue;
}
final childViewsOfParent =
await ViewBackendService.getChildViews(viewId: parentView.id)
.getOrThrow();
@ -165,7 +172,11 @@ class WorkspaceDataManager {
}
for (final view in orphanViews) {
Log.debug('[workspace] orphanViews: ${view.toProto3Json()}');
Log.info('[workspace] orphanViews: ${view.toProto3Json()}');
}
for (final view in rowPageViews) {
Log.info('[workspace] rowPageViews: ${view.toProto3Json()}');
}
if (!dryRun && unlistedChildViews.isNotEmpty) {

View File

@ -353,34 +353,37 @@ class _MToast extends StatelessWidget {
@override
Widget build(BuildContext context) {
final hintText = FlowyText.regular(
message,
fontSize: 16.0,
figmaLineHeight: 18.0,
color: Colors.white,
maxLines: 10,
);
return Container(
alignment: Alignment.bottomCenter,
padding: const EdgeInsets.only(bottom: 100),
padding: const EdgeInsets.only(bottom: 100, left: 16, right: 16),
child: Container(
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 13.0),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(12.0),
color: const Color(0xE5171717),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
if (type == ToastificationType.success) ...[
const FlowySvg(
FlowySvgs.success_s,
blendMode: null,
),
const HSpace(8.0),
],
FlowyText.regular(
message,
fontSize: 16.0,
figmaLineHeight: 18.0,
color: Colors.white,
maxLines: 3,
),
],
),
child: type == ToastificationType.success
? Row(
mainAxisSize: MainAxisSize.min,
children: [
if (type == ToastificationType.success) ...[
const FlowySvg(
FlowySvgs.success_s,
blendMode: null,
),
const HSpace(8.0),
],
hintText,
],
)
: hintText,
),
);
}

View File

@ -263,10 +263,12 @@ class FlowyButton extends StatelessWidget {
(Platform.isIOS || Platform.isAndroid)
? BoxDecoration(
border: Border.all(
color: borderColor ??
Theme.of(context).colorScheme.surfaceContainerHighest,
width: 1.0,
))
color: borderColor ??
Theme.of(context).colorScheme.outline,
width: 1.0,
),
borderRadius: radius,
)
: null);
return Container(

View File

@ -8,6 +8,7 @@ skip_pub_get=false
skip_pub_packages_get=false
verbose=false
exclude_packages=false
show_loading=false
# Parse command line arguments
while [[ $# -gt 0 ]]; do
@ -28,6 +29,10 @@ while [[ $# -gt 0 ]]; do
exclude_packages=true
shift
;;
--show-loading)
show_loading=true
shift
;;
*)
echo "Unknown option: $1"
exit 1
@ -111,11 +116,13 @@ fi
# Get the PID of the background process
build_pid=$!
# Start the loading animation
display_loading $build_pid &
if [ "$show_loading" = true ]; then
# Start the loading animation
display_loading $build_pid &
# Get the PID of the loading animation
loading_pid=$!
# Get the PID of the loading animation
loading_pid=$!
fi
# Wait for the build_runner to finish
wait $build_pid

View File

@ -64,7 +64,7 @@ cd ..
cd freezed
# Allow execution permissions on CI
chmod +x ./generate_freezed.sh
./generate_freezed.sh "${args[@]}"
./generate_freezed.sh "${args[@]}" --show-loading
# Return to the original directory
cd "$original_dir"