mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
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:
parent
e460120a1c
commit
7113269802
@ -18,14 +18,25 @@ extension MobileRouter on BuildContext {
|
|||||||
ViewPB view, {
|
ViewPB view, {
|
||||||
Map<String, dynamic>? arguments,
|
Map<String, dynamic>? arguments,
|
||||||
bool addInRecent = true,
|
bool addInRecent = true,
|
||||||
|
bool showMoreButton = true,
|
||||||
|
String? fixedTitle,
|
||||||
}) async {
|
}) async {
|
||||||
// set the current view before pushing the new view
|
// set the current view before pushing the new view
|
||||||
getIt<MenuSharedState>().latestOpenView = view;
|
getIt<MenuSharedState>().latestOpenView = view;
|
||||||
unawaited(getIt<CachedRecentService>().updateRecentViews([view.id], true));
|
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(
|
final uri = Uri(
|
||||||
path: view.routeName,
|
path: view.routeName,
|
||||||
queryParameters: view.queryParameters(arguments),
|
queryParameters: queryParameters,
|
||||||
).toString();
|
).toString();
|
||||||
await push(uri);
|
await push(uri);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,5 @@
|
|||||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
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_listener.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_service.dart';
|
|
||||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.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/prelude.dart';
|
||||||
import 'package:appflowy/workspace/application/view/view_ext.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 ViewPB view;
|
||||||
final DocumentListener _documentListener;
|
final DocumentListener _documentListener;
|
||||||
final ViewListener _viewListener;
|
final ViewListener _viewListener;
|
||||||
@ -124,16 +121,6 @@ class RecentViewBloc extends Bloc<RecentViewEvent, RecentViewState> {
|
|||||||
|
|
||||||
// for the version under 0.5.5
|
// for the version under 0.5.5
|
||||||
Future<(CoverType, String?)> getCoverV1() async {
|
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);
|
return (CoverType.none, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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/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/app_bar/app_bar.dart';
|
||||||
import 'package:appflowy/mobile/presentation/base/view_page/app_bar_buttons.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/mobile/presentation/widgets/flowy_mobile_state_container.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
|
import 'package:appflowy/plugins/document/presentation/document_collaborators.dart';
|
||||||
import 'package:appflowy/shared/feature_flags.dart';
|
import 'package:appflowy/shared/feature_flags.dart';
|
||||||
@ -26,6 +27,8 @@ class MobileViewPage extends StatefulWidget {
|
|||||||
required this.viewLayout,
|
required this.viewLayout,
|
||||||
this.title,
|
this.title,
|
||||||
this.arguments,
|
this.arguments,
|
||||||
|
this.fixedTitle,
|
||||||
|
this.showMoreButton = true,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// view id
|
/// view id
|
||||||
@ -33,6 +36,10 @@ class MobileViewPage extends StatefulWidget {
|
|||||||
final ViewLayoutPB viewLayout;
|
final ViewLayoutPB viewLayout;
|
||||||
final String? title;
|
final String? title;
|
||||||
final Map<String, dynamic>? arguments;
|
final Map<String, dynamic>? arguments;
|
||||||
|
final bool showMoreButton;
|
||||||
|
|
||||||
|
// only used in row page
|
||||||
|
final String? fixedTitle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MobileViewPage> createState() => _MobileViewPageState();
|
State<MobileViewPage> createState() => _MobileViewPageState();
|
||||||
@ -163,6 +170,9 @@ class _MobileViewPageState extends State<MobileViewPage> {
|
|||||||
return plugin.widgetBuilder.buildWidget(
|
return plugin.widgetBuilder.buildWidget(
|
||||||
shrinkWrap: false,
|
shrinkWrap: false,
|
||||||
context: PluginContext(userProfile: state.userProfilePB),
|
context: PluginContext(userProfile: state.userProfilePB),
|
||||||
|
data: {
|
||||||
|
MobileDocumentScreen.viewFixedTitle: widget.fixedTitle,
|
||||||
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
(error) {
|
(error) {
|
||||||
@ -215,13 +225,19 @@ class _MobileViewPageState extends State<MobileViewPage> {
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
actions.addAll([
|
if (widget.showMoreButton) {
|
||||||
MobileViewPageMoreButton(
|
actions.addAll([
|
||||||
view: view,
|
MobileViewPageMoreButton(
|
||||||
isImmersiveMode: isImmersiveMode,
|
view: view,
|
||||||
appBarOpacity: _appBarOpacity,
|
isImmersiveMode: isImmersiveMode,
|
||||||
),
|
appBarOpacity: _appBarOpacity,
|
||||||
]);
|
),
|
||||||
|
]);
|
||||||
|
} else {
|
||||||
|
actions.addAll([
|
||||||
|
const HSpace(18.0),
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -241,7 +257,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
|
|||||||
],
|
],
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FlowyText.medium(
|
child: FlowyText.medium(
|
||||||
view?.name ?? widget.title ?? '',
|
widget.fixedTitle ?? view?.name ?? widget.title ?? '',
|
||||||
fontSize: 15.0,
|
fontSize: 15.0,
|
||||||
overflow: TextOverflow.ellipsis,
|
overflow: TextOverflow.ellipsis,
|
||||||
figmaLineHeight: 18.0,
|
figmaLineHeight: 18.0,
|
||||||
|
@ -295,6 +295,7 @@ class MobileRowDetailPageContentState
|
|||||||
RowCache get rowCache => widget.databaseController.rowCache;
|
RowCache get rowCache => widget.databaseController.rowCache;
|
||||||
FieldController get fieldController =>
|
FieldController get fieldController =>
|
||||||
widget.databaseController.fieldController;
|
widget.databaseController.fieldController;
|
||||||
|
ValueNotifier<String> primaryFieldId = ValueNotifier('');
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -327,7 +328,13 @@ class MobileRowDetailPageContentState
|
|||||||
fieldController: fieldController,
|
fieldController: fieldController,
|
||||||
rowMeta: rowController.rowMeta,
|
rowMeta: rowController.rowMeta,
|
||||||
)..add(const RowBannerEvent.initial()),
|
)..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) {
|
builder: (context, state) {
|
||||||
if (state.primaryField == null) {
|
if (state.primaryField == null) {
|
||||||
return const SizedBox.shrink();
|
return const SizedBox.shrink();
|
||||||
@ -367,8 +374,22 @@ class MobileRowDetailPageContentState
|
|||||||
if (rowDetailState.numHiddenFields != 0) ...[
|
if (rowDetailState.numHiddenFields != 0) ...[
|
||||||
const ToggleHiddenFieldsVisibilityButton(),
|
const ToggleHiddenFieldsVisibilityButton(),
|
||||||
],
|
],
|
||||||
OpenRowPageButton(
|
const VSpace(8.0),
|
||||||
documentId: rowController.rowMeta.documentId,
|
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(
|
MobileRowDetailCreateFieldButton(
|
||||||
viewId: viewId,
|
viewId: viewId,
|
||||||
|
@ -22,7 +22,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
|
|||||||
return ConstrainedBox(
|
return ConstrainedBox(
|
||||||
constraints: BoxConstraints(
|
constraints: BoxConstraints(
|
||||||
minWidth: double.infinity,
|
minWidth: double.infinity,
|
||||||
minHeight: GridSize.headerHeight,
|
maxHeight: GridSize.headerHeight,
|
||||||
),
|
),
|
||||||
child: TextButton.icon(
|
child: TextButton.icon(
|
||||||
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
||||||
@ -37,7 +37,7 @@ class MobileRowDetailCreateFieldButton extends StatelessWidget {
|
|||||||
alignment: AlignmentDirectional.centerStart,
|
alignment: AlignmentDirectional.centerStart,
|
||||||
splashFactory: NoSplash.splashFactory,
|
splashFactory: NoSplash.splashFactory,
|
||||||
padding: const WidgetStatePropertyAll(
|
padding: const WidgetStatePropertyAll(
|
||||||
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
|
EdgeInsets.symmetric(horizontal: 6, vertical: 2),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
label: FlowyText.medium(
|
label: FlowyText.medium(
|
||||||
|
@ -3,6 +3,10 @@ import 'dart:async';
|
|||||||
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/mobile/application/mobile_router.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/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
import 'package:appflowy/workspace/application/view/prelude.dart';
|
import 'package:appflowy/workspace/application/view/prelude.dart';
|
||||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.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: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/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
class OpenRowPageButton extends StatefulWidget {
|
class OpenRowPageButton extends StatefulWidget {
|
||||||
const OpenRowPageButton({
|
const OpenRowPageButton({
|
||||||
super.key,
|
super.key,
|
||||||
required this.documentId,
|
required this.documentId,
|
||||||
|
required this.databaseController,
|
||||||
|
required this.cellContext,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String documentId;
|
final String documentId;
|
||||||
|
|
||||||
|
final DatabaseController databaseController;
|
||||||
|
final CellContext cellContext;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<OpenRowPageButton> createState() => _OpenRowPageButtonState();
|
State<OpenRowPageButton> createState() => _OpenRowPageButtonState();
|
||||||
}
|
}
|
||||||
|
|
||||||
class _OpenRowPageButtonState extends State<OpenRowPageButton> {
|
class _OpenRowPageButtonState extends State<OpenRowPageButton> {
|
||||||
|
late final cellBloc = TextCellBloc(
|
||||||
|
cellController: makeCellController(
|
||||||
|
widget.databaseController,
|
||||||
|
widget.cellContext,
|
||||||
|
).as(),
|
||||||
|
);
|
||||||
|
|
||||||
ViewPB? view;
|
ViewPB? view;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -36,44 +53,52 @@ class _OpenRowPageButtonState extends State<OpenRowPageButton> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ConstrainedBox(
|
return BlocBuilder<TextCellBloc, TextCellState>(
|
||||||
constraints: BoxConstraints(
|
bloc: cellBloc,
|
||||||
minWidth: double.infinity,
|
builder: (context, state) {
|
||||||
minHeight: GridSize.headerHeight,
|
return ConstrainedBox(
|
||||||
),
|
constraints: BoxConstraints(
|
||||||
child: TextButton.icon(
|
minWidth: double.infinity,
|
||||||
style: Theme.of(context).textButtonTheme.style?.copyWith(
|
maxHeight: GridSize.buttonHeight,
|
||||||
shape: WidgetStateProperty.all<RoundedRectangleBorder>(
|
),
|
||||||
RoundedRectangleBorder(
|
child: TextButton.icon(
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
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),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
label: FlowyText.medium(
|
||||||
overlayColor: WidgetStateProperty.all<Color>(
|
LocaleKeys.grid_field_openRowDocument.tr(),
|
||||||
Theme.of(context).hoverColor,
|
fontSize: 15,
|
||||||
),
|
),
|
||||||
alignment: AlignmentDirectional.centerStart,
|
icon: const Padding(
|
||||||
splashFactory: NoSplash.splashFactory,
|
padding: EdgeInsets.all(4.0),
|
||||||
padding: const WidgetStatePropertyAll(
|
child: FlowySvg(
|
||||||
EdgeInsets.symmetric(vertical: 14, horizontal: 6),
|
FlowySvgs.full_view_s,
|
||||||
|
size: Size.square(16.0),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
label: FlowyText.medium(
|
onPressed: () {
|
||||||
LocaleKeys.grid_field_openRowDocument.tr(),
|
final name = state.content;
|
||||||
fontSize: 15,
|
_openRowPage(context, name);
|
||||||
),
|
},
|
||||||
icon: const Padding(
|
|
||||||
padding: EdgeInsets.all(4.0),
|
|
||||||
child: FlowySvg(
|
|
||||||
FlowySvgs.full_view_s,
|
|
||||||
size: Size.square(16.0),
|
|
||||||
),
|
),
|
||||||
),
|
);
|
||||||
onPressed: () => _openRowPage(context),
|
},
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Future<void> _openRowPage(BuildContext context) async {
|
Future<void> _openRowPage(BuildContext context, String fieldName) async {
|
||||||
Log.info('Open row page(${widget.documentId})');
|
Log.info('Open row page(${widget.documentId})');
|
||||||
|
|
||||||
if (view == null) {
|
if (view == null) {
|
||||||
@ -89,6 +114,8 @@ class _OpenRowPageButtonState extends State<OpenRowPageButton> {
|
|||||||
await context.pushView(
|
await context.pushView(
|
||||||
view!,
|
view!,
|
||||||
addInRecent: false,
|
addInRecent: false,
|
||||||
|
showMoreButton: false,
|
||||||
|
fixedTitle: fieldName,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,15 +7,21 @@ class MobileDocumentScreen extends StatelessWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.id,
|
required this.id,
|
||||||
this.title,
|
this.title,
|
||||||
|
this.showMoreButton = true,
|
||||||
|
this.fixedTitle,
|
||||||
});
|
});
|
||||||
|
|
||||||
/// view id
|
/// view id
|
||||||
final String id;
|
final String id;
|
||||||
final String? title;
|
final String? title;
|
||||||
|
final bool showMoreButton;
|
||||||
|
final String? fixedTitle;
|
||||||
|
|
||||||
static const routeName = '/docs';
|
static const routeName = '/docs';
|
||||||
static const viewId = 'id';
|
static const viewId = 'id';
|
||||||
static const viewTitle = 'title';
|
static const viewTitle = 'title';
|
||||||
|
static const viewShowMoreButton = 'show_more_button';
|
||||||
|
static const viewFixedTitle = 'fixed_title';
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -23,6 +29,8 @@ class MobileDocumentScreen extends StatelessWidget {
|
|||||||
id: id,
|
id: id,
|
||||||
title: title,
|
title: title,
|
||||||
viewLayout: ViewLayoutPB.Document,
|
viewLayout: ViewLayoutPB.Document,
|
||||||
|
showMoreButton: showMoreButton,
|
||||||
|
fixedTitle: fixedTitle,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -96,36 +96,34 @@ class _FavoriteViews extends StatelessWidget {
|
|||||||
final borderColor = Theme.of(context).isLightMode
|
final borderColor = Theme.of(context).isLightMode
|
||||||
? const Color(0xFFE9E9EC)
|
? const Color(0xFFE9E9EC)
|
||||||
: const Color(0x1AFFFFFF);
|
: const Color(0x1AFFFFFF);
|
||||||
return Scrollbar(
|
return ListView.separated(
|
||||||
child: ListView.separated(
|
key: const PageStorageKey('favorite_views_page_storage_key'),
|
||||||
key: const PageStorageKey('favorite_views_page_storage_key'),
|
padding: EdgeInsets.only(
|
||||||
padding: EdgeInsets.only(
|
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
MediaQuery.of(context).padding.bottom,
|
||||||
MediaQuery.of(context).padding.bottom,
|
),
|
||||||
),
|
itemBuilder: (context, index) {
|
||||||
itemBuilder: (context, index) {
|
final view = favoriteViews[index];
|
||||||
final view = favoriteViews[index];
|
return Container(
|
||||||
return Container(
|
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
border: Border(
|
||||||
border: Border(
|
bottom: BorderSide(
|
||||||
bottom: BorderSide(
|
color: borderColor,
|
||||||
color: borderColor,
|
width: 0.5,
|
||||||
width: 0.5,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: MobileViewPage(
|
),
|
||||||
key: ValueKey(view.item.id),
|
child: MobileViewPage(
|
||||||
view: view.item,
|
key: ValueKey(view.item.id),
|
||||||
timestamp: view.timestamp,
|
view: view.item,
|
||||||
type: MobilePageCardType.favorite,
|
timestamp: view.timestamp,
|
||||||
),
|
type: MobilePageCardType.favorite,
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
separatorBuilder: (context, index) => const HSpace(8),
|
},
|
||||||
itemCount: favoriteViews.length,
|
separatorBuilder: (context, index) => const HSpace(8),
|
||||||
),
|
itemCount: favoriteViews.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,19 +25,17 @@ class _MobileHomeSpaceState extends State<MobileHomeSpace>
|
|||||||
final workspaceId =
|
final workspaceId =
|
||||||
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
|
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
|
||||||
'';
|
'';
|
||||||
return Scrollbar(
|
return SingleChildScrollView(
|
||||||
child: SingleChildScrollView(
|
child: Padding(
|
||||||
child: Padding(
|
padding: EdgeInsets.only(
|
||||||
padding: EdgeInsets.only(
|
top: HomeSpaceViewSizes.mVerticalPadding,
|
||||||
top: HomeSpaceViewSizes.mVerticalPadding,
|
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
MediaQuery.of(context).padding.bottom,
|
||||||
MediaQuery.of(context).padding.bottom,
|
),
|
||||||
),
|
child: MobileFolders(
|
||||||
child: MobileFolders(
|
user: widget.userProfile,
|
||||||
user: widget.userProfile,
|
workspaceId: workspaceId,
|
||||||
workspaceId: workspaceId,
|
showFavorite: false,
|
||||||
showFavorite: false,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -35,6 +35,9 @@ class MobileFolders extends StatelessWidget {
|
|||||||
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
|
context.read<UserWorkspaceBloc>().state.currentWorkspace?.workspaceId ??
|
||||||
'';
|
'';
|
||||||
return BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
|
return BlocListener<UserWorkspaceBloc, UserWorkspaceState>(
|
||||||
|
listenWhen: (previous, current) =>
|
||||||
|
previous.currentWorkspace?.workspaceId !=
|
||||||
|
current.currentWorkspace?.workspaceId,
|
||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
context.read<SidebarSectionsBloc>().add(
|
context.read<SidebarSectionsBloc>().add(
|
||||||
SidebarSectionsEvent.initial(
|
SidebarSectionsEvent.initial(
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
import 'dart:io';
|
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/mobile_home_page_header.dart';
|
||||||
import 'package:appflowy/mobile/presentation/home/tab/mobile_space_tab.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/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/startup/startup.dart';
|
||||||
import 'package:appflowy/user/application/auth/auth_service.dart';
|
import 'package:appflowy/user/application/auth/auth_service.dart';
|
||||||
import 'package:appflowy/user/application/reminder/reminder_bloc.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/errors/workspace_failed_screen.dart';
|
||||||
import 'package:appflowy/workspace/presentation/home/home_sizes.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/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/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/view.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/workspace.pb.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
import 'package:sentry/sentry.dart';
|
import 'package:sentry/sentry.dart';
|
||||||
|
import 'package:toastification/toastification.dart';
|
||||||
|
|
||||||
class MobileHomeScreen extends StatelessWidget {
|
class MobileHomeScreen extends StatelessWidget {
|
||||||
const MobileHomeScreen({super.key});
|
const MobileHomeScreen({super.key});
|
||||||
@ -103,6 +109,8 @@ class MobileHomePage extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MobileHomePageState extends State<MobileHomePage> {
|
class _MobileHomePageState extends State<MobileHomePage> {
|
||||||
|
Loading? loadingIndicator;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.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});
|
const _HomePage({required this.userProfile});
|
||||||
|
|
||||||
final UserProfilePB userProfile;
|
final UserProfilePB userProfile;
|
||||||
|
|
||||||
|
@override
|
||||||
|
State<_HomePage> createState() => _HomePageState();
|
||||||
|
}
|
||||||
|
|
||||||
|
class _HomePageState extends State<_HomePage> {
|
||||||
|
Loading? loadingIndicator;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
return BlocConsumer<UserWorkspaceBloc, UserWorkspaceState>(
|
||||||
@ -161,6 +176,8 @@ class _HomePage extends StatelessWidget {
|
|||||||
listener: (context, state) {
|
listener: (context, state) {
|
||||||
getIt<CachedRecentService>().reset();
|
getIt<CachedRecentService>().reset();
|
||||||
mCurrentWorkspace.value = state.currentWorkspace;
|
mCurrentWorkspace.value = state.currentWorkspace;
|
||||||
|
|
||||||
|
_showResultDialog(context, state);
|
||||||
},
|
},
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.currentWorkspace == null) {
|
if (state.currentWorkspace == null) {
|
||||||
@ -170,6 +187,7 @@ class _HomePage extends StatelessWidget {
|
|||||||
final workspaceId = state.currentWorkspace!.workspaceId;
|
final workspaceId = state.currentWorkspace!.workspaceId;
|
||||||
|
|
||||||
return Column(
|
return Column(
|
||||||
|
key: ValueKey('mobile_home_page_$workspaceId'),
|
||||||
children: [
|
children: [
|
||||||
// Header
|
// Header
|
||||||
Padding(
|
Padding(
|
||||||
@ -179,7 +197,7 @@ class _HomePage extends StatelessWidget {
|
|||||||
top: Platform.isAndroid ? 8.0 : 0.0,
|
top: Platform.isAndroid ? 8.0 : 0.0,
|
||||||
),
|
),
|
||||||
child: MobileHomePageHeader(
|
child: MobileHomePageHeader(
|
||||||
userProfile: userProfile,
|
userProfile: widget.userProfile,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
|
||||||
@ -194,7 +212,7 @@ class _HomePage extends StatelessWidget {
|
|||||||
create: (_) => SidebarSectionsBloc()
|
create: (_) => SidebarSectionsBloc()
|
||||||
..add(
|
..add(
|
||||||
SidebarSectionsEvent.initial(
|
SidebarSectionsEvent.initial(
|
||||||
userProfile,
|
widget.userProfile,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
@ -207,7 +225,7 @@ class _HomePage extends StatelessWidget {
|
|||||||
create: (_) => SpaceBloc()
|
create: (_) => SpaceBloc()
|
||||||
..add(
|
..add(
|
||||||
SpaceEvent.initial(
|
SpaceEvent.initial(
|
||||||
userProfile,
|
widget.userProfile,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
openFirstPage: false,
|
openFirstPage: false,
|
||||||
),
|
),
|
||||||
@ -215,7 +233,7 @@ class _HomePage extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
child: MobileSpaceTab(
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -68,36 +68,34 @@ class _RecentViews extends StatelessWidget {
|
|||||||
? const Color(0xFFE9E9EC)
|
? const Color(0xFFE9E9EC)
|
||||||
: const Color(0x1AFFFFFF);
|
: const Color(0x1AFFFFFF);
|
||||||
return SlidableAutoCloseBehavior(
|
return SlidableAutoCloseBehavior(
|
||||||
child: Scrollbar(
|
child: ListView.separated(
|
||||||
child: ListView.separated(
|
key: const PageStorageKey('recent_views_page_storage_key'),
|
||||||
key: const PageStorageKey('recent_views_page_storage_key'),
|
padding: EdgeInsets.only(
|
||||||
padding: EdgeInsets.only(
|
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
MediaQuery.of(context).padding.bottom,
|
||||||
MediaQuery.of(context).padding.bottom,
|
),
|
||||||
),
|
itemBuilder: (context, index) {
|
||||||
itemBuilder: (context, index) {
|
final sectionView = recentViews[index];
|
||||||
final sectionView = recentViews[index];
|
return Container(
|
||||||
return Container(
|
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
||||||
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
decoration: BoxDecoration(
|
||||||
decoration: BoxDecoration(
|
border: Border(
|
||||||
border: Border(
|
bottom: BorderSide(
|
||||||
bottom: BorderSide(
|
color: borderColor,
|
||||||
color: borderColor,
|
width: 0.5,
|
||||||
width: 0.5,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
child: MobileViewPage(
|
),
|
||||||
key: ValueKey(sectionView.item.id),
|
child: MobileViewPage(
|
||||||
view: sectionView.item,
|
key: ValueKey(sectionView.item.id),
|
||||||
timestamp: sectionView.timestamp,
|
view: sectionView.item,
|
||||||
type: MobilePageCardType.recent,
|
timestamp: sectionView.timestamp,
|
||||||
),
|
type: MobilePageCardType.recent,
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
separatorBuilder: (context, index) => const HSpace(8),
|
},
|
||||||
itemCount: recentViews.length,
|
separatorBuilder: (context, index) => const HSpace(8),
|
||||||
),
|
itemCount: recentViews.length,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,8 @@ import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
|||||||
import 'package:appflowy/shared/appflowy_cache_manager.dart';
|
import 'package:appflowy/shared/appflowy_cache_manager.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/util/share_log_files.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: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/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -74,10 +75,14 @@ class SupportSettingGroup extends StatelessWidget {
|
|||||||
actionButtonTitle: LocaleKeys.button_yes.tr(),
|
actionButtonTitle: LocaleKeys.button_yes.tr(),
|
||||||
onActionButtonPressed: () async {
|
onActionButtonPressed: () async {
|
||||||
await getIt<FlowyCacheManager>().clearAllCache();
|
await getIt<FlowyCacheManager>().clearAllCache();
|
||||||
|
// check the workspace and space health
|
||||||
|
await WorkspaceDataManager.checkViewHealth(
|
||||||
|
dryRun: false,
|
||||||
|
);
|
||||||
if (context.mounted) {
|
if (context.mounted) {
|
||||||
showSnackBarMessage(
|
showToastNotification(
|
||||||
context,
|
context,
|
||||||
LocaleKeys.settings_files_clearCacheSuccess.tr(),
|
message: LocaleKeys.settings_files_clearCacheSuccess.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
@ -48,6 +48,7 @@ class _InviteMemberPage extends StatefulWidget {
|
|||||||
class _InviteMemberPageState extends State<_InviteMemberPage> {
|
class _InviteMemberPageState extends State<_InviteMemberPage> {
|
||||||
final emailController = TextEditingController();
|
final emailController = TextEditingController();
|
||||||
late final Future<UserProfilePB?> userProfile;
|
late final Future<UserProfilePB?> userProfile;
|
||||||
|
bool exceededLimit = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -131,6 +132,15 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
const VSpace(16),
|
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(
|
SizedBox(
|
||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: ElevatedButton(
|
child: ElevatedButton(
|
||||||
@ -197,6 +207,9 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
|
|||||||
final message = f.code == ErrorCode.WorkspaceMemberLimitExceeded
|
final message = f.code == ErrorCode.WorkspaceMemberLimitExceeded
|
||||||
? LocaleKeys.settings_appearance_members_memberLimitExceeded.tr()
|
? LocaleKeys.settings_appearance_members_memberLimitExceeded.tr()
|
||||||
: LocaleKeys.settings_appearance_members_failedToAddMember.tr();
|
: LocaleKeys.settings_appearance_members_failedToAddMember.tr();
|
||||||
|
setState(() {
|
||||||
|
exceededLimit = f.code == ErrorCode.WorkspaceMemberLimitExceeded;
|
||||||
|
});
|
||||||
showToastNotification(
|
showToastNotification(
|
||||||
context,
|
context,
|
||||||
type: ToastificationType.error,
|
type: ToastificationType.error,
|
||||||
@ -220,6 +233,9 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
|
|||||||
.tr()
|
.tr()
|
||||||
: LocaleKeys.settings_appearance_members_failedToInviteMember
|
: LocaleKeys.settings_appearance_members_failedToInviteMember
|
||||||
.tr();
|
.tr();
|
||||||
|
setState(() {
|
||||||
|
exceededLimit = f.code == ErrorCode.WorkspaceMemberLimitExceeded;
|
||||||
|
});
|
||||||
showToastNotification(
|
showToastNotification(
|
||||||
context,
|
context,
|
||||||
type: ToastificationType.error,
|
type: ToastificationType.error,
|
||||||
@ -255,6 +271,7 @@ class _InviteMemberPageState extends State<_InviteMemberPage> {
|
|||||||
if (!isEmail(email)) {
|
if (!isEmail(email)) {
|
||||||
return showToastNotification(
|
return showToastNotification(
|
||||||
context,
|
context,
|
||||||
|
type: ToastificationType.error,
|
||||||
message: LocaleKeys.settings_appearance_members_emailInvalidError.tr(),
|
message: LocaleKeys.settings_appearance_members_emailInvalidError.tr(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -425,13 +425,14 @@ class _ChatContentPageState extends State<_ChatContentPage> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
const VSpace(6),
|
const VSpace(6),
|
||||||
Opacity(
|
if (PlatformExtension.isDesktop)
|
||||||
opacity: 0.6,
|
Opacity(
|
||||||
child: FlowyText(
|
opacity: 0.6,
|
||||||
LocaleKeys.chat_aiMistakePrompt.tr(),
|
child: FlowyText(
|
||||||
fontSize: 12,
|
LocaleKeys.chat_aiMistakePrompt.tr(),
|
||||||
|
fontSize: 12,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -6,6 +6,7 @@ class GridSize {
|
|||||||
|
|
||||||
static double get scrollBarSize => 8 * scale;
|
static double get scrollBarSize => 8 * scale;
|
||||||
static double get headerHeight => 40 * scale;
|
static double get headerHeight => 40 * scale;
|
||||||
|
static double get buttonHeight => 38 * scale;
|
||||||
static double get footerHeight => 40 * scale;
|
static double get footerHeight => 40 * scale;
|
||||||
static double get horizontalHeaderPadding =>
|
static double get horizontalHeaderPadding =>
|
||||||
PlatformExtension.isDesktop ? 40 * scale : 16 * scale;
|
PlatformExtension.isDesktop ? 40 * scale : 16 * scale;
|
||||||
|
@ -188,8 +188,14 @@ class _RowMenuButtonState extends State<RowMenuButton> {
|
|||||||
richTooltipText: widget.isDragEnabled
|
richTooltipText: widget.isDragEnabled
|
||||||
? TextSpan(
|
? TextSpan(
|
||||||
children: [
|
children: [
|
||||||
TextSpan(text: '${LocaleKeys.tooltip_dragRow.tr()}\n'),
|
TextSpan(
|
||||||
TextSpan(text: LocaleKeys.tooltip_openMenu.tr()),
|
text: '${LocaleKeys.tooltip_dragRow.tr()}\n',
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
|
),
|
||||||
|
TextSpan(
|
||||||
|
text: LocaleKeys.tooltip_openMenu.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
: null,
|
: null,
|
||||||
|
@ -13,42 +13,54 @@ class MobileRowDetailSummaryCellSkin extends IEditableSummaryCellSkin {
|
|||||||
FocusNode focusNode,
|
FocusNode focusNode,
|
||||||
TextEditingController textEditingController,
|
TextEditingController textEditingController,
|
||||||
) {
|
) {
|
||||||
return Column(
|
return Container(
|
||||||
children: [
|
decoration: BoxDecoration(
|
||||||
TextField(
|
border: Border.fromBorderSide(
|
||||||
controller: textEditingController,
|
BorderSide(color: Theme.of(context).colorScheme.outline),
|
||||||
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(
|
borderRadius: const BorderRadius.all(Radius.circular(14)),
|
||||||
children: [
|
),
|
||||||
const Spacer(),
|
padding: const EdgeInsets.symmetric(
|
||||||
Padding(
|
horizontal: 4,
|
||||||
padding: const EdgeInsets.all(8.0),
|
vertical: 2,
|
||||||
child: SummaryCellAccessory(
|
),
|
||||||
viewId: bloc.cellController.viewId,
|
child: Column(
|
||||||
fieldId: bloc.cellController.fieldId,
|
children: [
|
||||||
rowId: bloc.cellController.rowId,
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,42 +13,54 @@ class MobileRowDetailTranslateCellSkin extends IEditableTranslateCellSkin {
|
|||||||
FocusNode focusNode,
|
FocusNode focusNode,
|
||||||
TextEditingController textEditingController,
|
TextEditingController textEditingController,
|
||||||
) {
|
) {
|
||||||
return Column(
|
return Container(
|
||||||
children: [
|
decoration: BoxDecoration(
|
||||||
TextField(
|
border: Border.fromBorderSide(
|
||||||
readOnly: true,
|
BorderSide(color: Theme.of(context).colorScheme.outline),
|
||||||
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(
|
borderRadius: const BorderRadius.all(Radius.circular(14)),
|
||||||
children: [
|
),
|
||||||
const Spacer(),
|
padding: const EdgeInsets.symmetric(
|
||||||
Padding(
|
horizontal: 4,
|
||||||
padding: const EdgeInsets.all(8.0),
|
vertical: 2,
|
||||||
child: TranslateCellAccessory(
|
),
|
||||||
viewId: bloc.cellController.viewId,
|
child: Column(
|
||||||
fieldId: bloc.cellController.fieldId,
|
children: [
|
||||||
rowId: bloc.cellController.rowId,
|
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,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,5 @@
|
|||||||
import 'dart:io';
|
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/flowy_svgs.g.dart';
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller.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:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.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/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../cell/editable_cell_builder.dart';
|
import '../cell/editable_cell_builder.dart';
|
||||||
|
|
||||||
import 'accessory/cell_accessory.dart';
|
import 'accessory/cell_accessory.dart';
|
||||||
|
|
||||||
/// Display the row properties in a list. Only used in [RowDetailPage].
|
/// 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,
|
svg: FlowySvgs.drag_element_s,
|
||||||
richMessage: TextSpan(
|
richMessage: TextSpan(
|
||||||
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
|
text: LocaleKeys.grid_rowPage_fieldDragElementTooltip.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
@ -2,6 +2,7 @@ library document_plugin;
|
|||||||
|
|
||||||
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/mobile/presentation/presentation.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||||
import 'package:appflowy/plugins/document/document_page.dart';
|
import 'package:appflowy/plugins/document/document_page.dart';
|
||||||
import 'package:appflowy/plugins/document/presentation/document_collaborators.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(
|
return BlocProvider<ViewInfoBloc>.value(
|
||||||
value: bloc,
|
value: bloc,
|
||||||
child: BlocBuilder<DocumentAppearanceCubit, DocumentAppearance>(
|
child: BlocBuilder<DocumentAppearanceCubit, DocumentAppearance>(
|
||||||
@ -126,6 +129,7 @@ class DocumentPluginWidgetBuilder extends PluginWidgetBuilder
|
|||||||
view: view,
|
view: view,
|
||||||
onDeleted: () => context.onDeleted?.call(view, deletedViewIndex),
|
onDeleted: () => context.onDeleted?.call(view, deletedViewIndex),
|
||||||
initialSelection: initialSelection,
|
initialSelection: initialSelection,
|
||||||
|
fixedTitle: fixedTitle,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||||
import 'package:appflowy/plugins/document/application/document_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:desktop_drop/desktop_drop.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/widget/error_page.dart';
|
import 'package:flowy_infra_ui/widget/error_page.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
@ -42,11 +41,13 @@ class DocumentPage extends StatefulWidget {
|
|||||||
required this.view,
|
required this.view,
|
||||||
required this.onDeleted,
|
required this.onDeleted,
|
||||||
this.initialSelection,
|
this.initialSelection,
|
||||||
|
this.fixedTitle,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
final VoidCallback onDeleted;
|
final VoidCallback onDeleted;
|
||||||
final Selection? initialSelection;
|
final Selection? initialSelection;
|
||||||
|
final String? fixedTitle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DocumentPage> createState() => _DocumentPageState();
|
State<DocumentPage> createState() => _DocumentPageState();
|
||||||
@ -103,6 +104,7 @@ class _DocumentPageState extends State<DocumentPage>
|
|||||||
BlocProvider.value(value: documentBloc),
|
BlocProvider.value(value: documentBloc),
|
||||||
],
|
],
|
||||||
child: BlocBuilder<DocumentBloc, DocumentState>(
|
child: BlocBuilder<DocumentBloc, DocumentState>(
|
||||||
|
buildWhen: _shouldRebuildDocument,
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.isLoading) {
|
if (state.isLoading) {
|
||||||
return const Center(child: CircularProgressIndicator.adaptive());
|
return const Center(child: CircularProgressIndicator.adaptive());
|
||||||
@ -261,6 +263,7 @@ class _DocumentPageState extends State<DocumentPage>
|
|||||||
|
|
||||||
if (PlatformExtension.isMobile) {
|
if (PlatformExtension.isMobile) {
|
||||||
return DocumentImmersiveCover(
|
return DocumentImmersiveCover(
|
||||||
|
fixedTitle: widget.fixedTitle,
|
||||||
view: widget.view,
|
view: widget.view,
|
||||||
userProfilePB: userProfilePB,
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -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/plugins/document/presentation/editor_plugins/actions/block_action_button.dart';
|
||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
@ -31,16 +32,19 @@ class BlockAddButton extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: LocaleKeys.blockActions_addBelowTooltip.tr(),
|
text: LocaleKeys.blockActions_addBelowTooltip.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
const TextSpan(text: '\n'),
|
const TextSpan(text: '\n'),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: Platform.isMacOS
|
text: Platform.isMacOS
|
||||||
? LocaleKeys.blockActions_addAboveMacCmd.tr()
|
? LocaleKeys.blockActions_addAboveMacCmd.tr()
|
||||||
: LocaleKeys.blockActions_addAboveCmd.tr(),
|
: LocaleKeys.blockActions_addAboveCmd.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
const TextSpan(text: ' '),
|
const TextSpan(text: ' '),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: LocaleKeys.blockActions_addAboveTooltip.tr(),
|
text: LocaleKeys.blockActions_addAboveTooltip.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -21,7 +21,6 @@ class BlockActionButton extends StatelessWidget {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Align(
|
return Align(
|
||||||
child: FlowyTooltip(
|
child: FlowyTooltip(
|
||||||
preferBelow: false,
|
|
||||||
richMessage: richMessage,
|
richMessage: richMessage,
|
||||||
child: MouseRegion(
|
child: MouseRegion(
|
||||||
cursor: Platform.isWindows
|
cursor: Platform.isWindows
|
||||||
|
@ -7,6 +7,7 @@ import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
|
|||||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
import 'package:appflowy_editor/appflowy_editor.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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
@ -67,11 +68,14 @@ class BlockOptionButton extends StatelessWidget {
|
|||||||
controller.close();
|
controller.close();
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
buildChild: (controller) => _buildOptionButton(controller),
|
buildChild: (controller) => _buildOptionButton(context, controller),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildOptionButton(PopoverController controller) {
|
Widget _buildOptionButton(
|
||||||
|
BuildContext context,
|
||||||
|
PopoverController controller,
|
||||||
|
) {
|
||||||
return BlockActionButton(
|
return BlockActionButton(
|
||||||
svg: FlowySvgs.drag_element_s,
|
svg: FlowySvgs.drag_element_s,
|
||||||
richMessage: TextSpan(
|
richMessage: TextSpan(
|
||||||
@ -79,9 +83,11 @@ class BlockOptionButton extends StatelessWidget {
|
|||||||
TextSpan(
|
TextSpan(
|
||||||
// todo: customize the color to highlight the text.
|
// todo: customize the color to highlight the text.
|
||||||
text: LocaleKeys.document_plugins_optionAction_click.tr(),
|
text: LocaleKeys.document_plugins_optionAction_click.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
TextSpan(
|
TextSpan(
|
||||||
text: LocaleKeys.document_plugins_optionAction_toOpenMenu.tr(),
|
text: LocaleKeys.document_plugins_optionAction_toOpenMenu.tr(),
|
||||||
|
style: context.tooltipTextStyle(),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -34,10 +34,12 @@ class DocumentImmersiveCover extends StatefulWidget {
|
|||||||
super.key,
|
super.key,
|
||||||
required this.view,
|
required this.view,
|
||||||
required this.userProfilePB,
|
required this.userProfilePB,
|
||||||
|
this.fixedTitle,
|
||||||
});
|
});
|
||||||
|
|
||||||
final ViewPB view;
|
final ViewPB view;
|
||||||
final UserProfilePB userProfilePB;
|
final UserProfilePB userProfilePB;
|
||||||
|
final String? fixedTitle;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<DocumentImmersiveCover> createState() => _DocumentImmersiveCoverState();
|
State<DocumentImmersiveCover> createState() => _DocumentImmersiveCoverState();
|
||||||
@ -143,6 +145,18 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
|
|||||||
fontFamily = getGoogleFontSafely(documentFontFamily).fontFamily;
|
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(
|
return AutoSizeTextField(
|
||||||
controller: textEditingController,
|
controller: textEditingController,
|
||||||
focusNode: focusNode,
|
focusNode: focusNode,
|
||||||
|
@ -121,38 +121,36 @@ class _UploadImageMenuState extends State<UploadImageMenu> {
|
|||||||
final type = values[currentTabIndex];
|
final type = values[currentTabIndex];
|
||||||
switch (type) {
|
switch (type) {
|
||||||
case UploadImageType.local:
|
case UploadImageType.local:
|
||||||
return Column(
|
Widget child = UploadImageFileWidget(
|
||||||
children: [
|
allowMultipleImages: widget.allowMultipleImages,
|
||||||
Padding(
|
onPickFiles: widget.onSelectedLocalImages,
|
||||||
padding: const EdgeInsets.all(8.0),
|
);
|
||||||
child: Container(
|
if (PlatformExtension.isDesktop) {
|
||||||
alignment: Alignment.center,
|
child = Padding(
|
||||||
decoration: BoxDecoration(
|
padding: const EdgeInsets.all(8.0),
|
||||||
borderRadius: BorderRadius.circular(8),
|
child: Container(
|
||||||
border: Border.all(
|
alignment: Alignment.center,
|
||||||
color: Theme.of(context).colorScheme.outline,
|
decoration: BoxDecoration(
|
||||||
),
|
borderRadius: BorderRadius.circular(8),
|
||||||
),
|
border: Border.all(
|
||||||
constraints: constraints,
|
color: Theme.of(context).colorScheme.outline,
|
||||||
child: Column(
|
|
||||||
children: [
|
|
||||||
UploadImageFileWidget(
|
|
||||||
allowMultipleImages: widget.allowMultipleImages,
|
|
||||||
onPickFiles: widget.onSelectedLocalImages,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
constraints: constraints,
|
||||||
|
child: child,
|
||||||
),
|
),
|
||||||
// if (widget.limitMaximumImageSize) ...[
|
);
|
||||||
// FlowyText(
|
} else {
|
||||||
// LocaleKeys.document_imageBlock_maximumImageSize.tr(),
|
child = Padding(
|
||||||
// fontSize: 10.0,
|
padding: const EdgeInsets.symmetric(
|
||||||
// color: Theme.of(context).hintColor,
|
horizontal: 8.0,
|
||||||
// ),
|
vertical: 12.0,
|
||||||
// ],
|
),
|
||||||
],
|
child: child,
|
||||||
);
|
);
|
||||||
|
}
|
||||||
|
return child;
|
||||||
|
|
||||||
case UploadImageType.url:
|
case UploadImageType.url:
|
||||||
return Container(
|
return Container(
|
||||||
padding: const EdgeInsets.all(8.0),
|
padding: const EdgeInsets.all(8.0),
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/patterns/common_patterns.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: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/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -22,14 +23,27 @@ class _EmbedImageUrlWidgetState extends State<EmbedImageUrlWidget> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
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(
|
return Column(
|
||||||
children: [
|
children: [
|
||||||
const VSpace(12),
|
const VSpace(12),
|
||||||
FlowyTextField(
|
PlatformExtension.isDesktop
|
||||||
hintText: LocaleKeys.document_imageBlock_embedLink_placeholder.tr(),
|
? textField
|
||||||
onChanged: (value) => inputText = value,
|
: SizedBox(
|
||||||
onEditingComplete: submit,
|
height: 42,
|
||||||
),
|
child: textField,
|
||||||
|
),
|
||||||
if (!isUrlValid) ...[
|
if (!isUrlValid) ...[
|
||||||
const VSpace(12),
|
const VSpace(12),
|
||||||
FlowyText(
|
FlowyText(
|
||||||
@ -39,18 +53,23 @@ class _EmbedImageUrlWidgetState extends State<EmbedImageUrlWidget> {
|
|||||||
],
|
],
|
||||||
const VSpace(20),
|
const VSpace(20),
|
||||||
SizedBox(
|
SizedBox(
|
||||||
height: 32,
|
height: PlatformExtension.isMobile ? 36 : 32,
|
||||||
width: 300,
|
width: 300,
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||||
hoverColor: Theme.of(context).colorScheme.primary.withOpacity(0.9),
|
hoverColor: Theme.of(context).colorScheme.primary.withOpacity(0.9),
|
||||||
showDefaultBoxDecorationOnMobile: true,
|
showDefaultBoxDecorationOnMobile: true,
|
||||||
|
radius:
|
||||||
|
PlatformExtension.isMobile ? BorderRadius.circular(8) : null,
|
||||||
margin: const EdgeInsets.all(5),
|
margin: const EdgeInsets.all(5),
|
||||||
text: FlowyText(
|
text: FlowyText(
|
||||||
LocaleKeys.document_imageBlock_embedLink_label.tr(),
|
LocaleKeys.document_imageBlock_embedLink_label.tr(),
|
||||||
lineHeight: 1,
|
lineHeight: 1,
|
||||||
textAlign: TextAlign.center,
|
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,
|
onTap: submit,
|
||||||
),
|
),
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||||
import 'package:appflowy/shared/permission/permission_checker.dart';
|
import 'package:appflowy/shared/permission/permission_checker.dart';
|
||||||
import 'package:appflowy/startup/startup.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/file_picker/file_picker_service.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
import 'package:image_picker/image_picker.dart';
|
import 'package:image_picker/image_picker.dart';
|
||||||
|
|
||||||
class UploadImageFileWidget extends StatelessWidget {
|
class UploadImageFileWidget extends StatelessWidget {
|
||||||
@ -25,8 +24,9 @@ class UploadImageFileWidget extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final child = FlowyButton(
|
Widget child = FlowyButton(
|
||||||
showDefaultBoxDecorationOnMobile: true,
|
showDefaultBoxDecorationOnMobile: true,
|
||||||
|
radius: PlatformExtension.isMobile ? BorderRadius.circular(8.0) : null,
|
||||||
text: Container(
|
text: Container(
|
||||||
margin: const EdgeInsets.all(4.0),
|
margin: const EdgeInsets.all(4.0),
|
||||||
alignment: Alignment.center,
|
alignment: Alignment.center,
|
||||||
@ -38,7 +38,12 @@ class UploadImageFileWidget extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
if (PlatformExtension.isDesktopOrWeb) {
|
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;
|
return child;
|
||||||
|
@ -8,12 +8,22 @@ class Loading {
|
|||||||
BuildContext? loadingContext;
|
BuildContext? loadingContext;
|
||||||
final BuildContext context;
|
final BuildContext context;
|
||||||
|
|
||||||
|
bool hasStopped = false;
|
||||||
|
|
||||||
void start() => unawaited(
|
void start() => unawaited(
|
||||||
showDialog<void>(
|
showDialog<void>(
|
||||||
context: context,
|
context: context,
|
||||||
barrierDismissible: false,
|
barrierDismissible: false,
|
||||||
builder: (BuildContext context) {
|
builder: (BuildContext context) {
|
||||||
loadingContext = context;
|
loadingContext = context;
|
||||||
|
|
||||||
|
if (hasStopped) {
|
||||||
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
|
Navigator.of(loadingContext!).pop();
|
||||||
|
loadingContext = null;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
return const SimpleDialog(
|
return const SimpleDialog(
|
||||||
elevation: 0.0,
|
elevation: 0.0,
|
||||||
backgroundColor:
|
backgroundColor:
|
||||||
@ -33,6 +43,8 @@ class Loading {
|
|||||||
Navigator.of(loadingContext!).pop();
|
Navigator.of(loadingContext!).pop();
|
||||||
loadingContext = null;
|
loadingContext = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
hasStopped = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -493,9 +493,20 @@ GoRoute _mobileEditorScreenRoute() {
|
|||||||
pageBuilder: (context, state) {
|
pageBuilder: (context, state) {
|
||||||
final id = state.uri.queryParameters[MobileDocumentScreen.viewId]!;
|
final id = state.uri.queryParameters[MobileDocumentScreen.viewId]!;
|
||||||
final title = state.uri.queryParameters[MobileDocumentScreen.viewTitle];
|
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(
|
return MaterialExtendedPage(
|
||||||
child: MobileDocumentScreen(id: id, title: title),
|
child: MobileDocumentScreen(
|
||||||
|
id: id,
|
||||||
|
title: title,
|
||||||
|
showMoreButton: showMoreButton ?? true,
|
||||||
|
fixedTitle: fixedTitle,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
@ -33,7 +33,7 @@ class CachedRecentService {
|
|||||||
final _listener = RecentViewsListener();
|
final _listener = RecentViewsListener();
|
||||||
|
|
||||||
Future<List<SectionViewPB>> recentViews() async {
|
Future<List<SectionViewPB>> recentViews() async {
|
||||||
if (_isInitialized) return _recentViews;
|
if (_isInitialized || _completer.isCompleted) return _recentViews;
|
||||||
|
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
@ -76,7 +76,10 @@ class CachedRecentService {
|
|||||||
(recentViews) {
|
(recentViews) {
|
||||||
return FlowyResult.success(
|
return FlowyResult.success(
|
||||||
RepeatedRecentViewPB(
|
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,
|
||||||
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -68,6 +68,8 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
await event.when(
|
await event.when(
|
||||||
initial: (userProfile, workspaceId, openFirstPage) async {
|
initial: (userProfile, workspaceId, openFirstPage) async {
|
||||||
|
this.openFirstPage = openFirstPage;
|
||||||
|
|
||||||
_initial(userProfile, workspaceId);
|
_initial(userProfile, workspaceId);
|
||||||
|
|
||||||
final (spaces, publicViews, privateViews) = await _getSpaces();
|
final (spaces, publicViews, privateViews) = await _getSpaces();
|
||||||
@ -305,7 +307,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
SpaceEvent.initial(
|
SpaceEvent.initial(
|
||||||
userProfile,
|
userProfile,
|
||||||
workspaceId,
|
workspaceId,
|
||||||
openFirstPage: true,
|
openFirstPage: openFirstPage,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
@ -353,6 +355,7 @@ class SpaceBloc extends Bloc<SpaceEvent, SpaceState> {
|
|||||||
String? _workspaceId;
|
String? _workspaceId;
|
||||||
late UserProfilePB userProfile;
|
late UserProfilePB userProfile;
|
||||||
WorkspaceSectionsListener? _listener;
|
WorkspaceSectionsListener? _listener;
|
||||||
|
bool openFirstPage = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
|
@ -118,6 +118,8 @@ class WorkspaceDataManager {
|
|||||||
final List<ViewPB> unlistedChildViews = [];
|
final List<ViewPB> unlistedChildViews = [];
|
||||||
// Views whose parent is not in allViews
|
// Views whose parent is not in allViews
|
||||||
final List<ViewPB> orphanViews = [];
|
final List<ViewPB> orphanViews = [];
|
||||||
|
// Row pages
|
||||||
|
final List<ViewPB> rowPageViews = [];
|
||||||
|
|
||||||
try {
|
try {
|
||||||
if (workspace == null || allViews == null) {
|
if (workspace == null || allViews == null) {
|
||||||
@ -145,6 +147,11 @@ class WorkspaceDataManager {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (parentView.id == view.id) {
|
||||||
|
rowPageViews.add(view);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
final childViewsOfParent =
|
final childViewsOfParent =
|
||||||
await ViewBackendService.getChildViews(viewId: parentView.id)
|
await ViewBackendService.getChildViews(viewId: parentView.id)
|
||||||
.getOrThrow();
|
.getOrThrow();
|
||||||
@ -165,7 +172,11 @@ class WorkspaceDataManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (final view in orphanViews) {
|
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) {
|
if (!dryRun && unlistedChildViews.isNotEmpty) {
|
||||||
|
@ -353,34 +353,37 @@ class _MToast extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final hintText = FlowyText.regular(
|
||||||
|
message,
|
||||||
|
fontSize: 16.0,
|
||||||
|
figmaLineHeight: 18.0,
|
||||||
|
color: Colors.white,
|
||||||
|
maxLines: 10,
|
||||||
|
);
|
||||||
return Container(
|
return Container(
|
||||||
alignment: Alignment.bottomCenter,
|
alignment: Alignment.bottomCenter,
|
||||||
padding: const EdgeInsets.only(bottom: 100),
|
padding: const EdgeInsets.only(bottom: 100, left: 16, right: 16),
|
||||||
child: Container(
|
child: Container(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 13.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0, vertical: 13.0),
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
borderRadius: BorderRadius.circular(12.0),
|
borderRadius: BorderRadius.circular(12.0),
|
||||||
color: const Color(0xE5171717),
|
color: const Color(0xE5171717),
|
||||||
),
|
),
|
||||||
child: Row(
|
child: type == ToastificationType.success
|
||||||
mainAxisSize: MainAxisSize.min,
|
? Row(
|
||||||
children: [
|
mainAxisSize: MainAxisSize.min,
|
||||||
if (type == ToastificationType.success) ...[
|
children: [
|
||||||
const FlowySvg(
|
if (type == ToastificationType.success) ...[
|
||||||
FlowySvgs.success_s,
|
const FlowySvg(
|
||||||
blendMode: null,
|
FlowySvgs.success_s,
|
||||||
),
|
blendMode: null,
|
||||||
const HSpace(8.0),
|
),
|
||||||
],
|
const HSpace(8.0),
|
||||||
FlowyText.regular(
|
],
|
||||||
message,
|
hintText,
|
||||||
fontSize: 16.0,
|
],
|
||||||
figmaLineHeight: 18.0,
|
)
|
||||||
color: Colors.white,
|
: hintText,
|
||||||
maxLines: 3,
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -263,10 +263,12 @@ class FlowyButton extends StatelessWidget {
|
|||||||
(Platform.isIOS || Platform.isAndroid)
|
(Platform.isIOS || Platform.isAndroid)
|
||||||
? BoxDecoration(
|
? BoxDecoration(
|
||||||
border: Border.all(
|
border: Border.all(
|
||||||
color: borderColor ??
|
color: borderColor ??
|
||||||
Theme.of(context).colorScheme.surfaceContainerHighest,
|
Theme.of(context).colorScheme.outline,
|
||||||
width: 1.0,
|
width: 1.0,
|
||||||
))
|
),
|
||||||
|
borderRadius: radius,
|
||||||
|
)
|
||||||
: null);
|
: null);
|
||||||
|
|
||||||
return Container(
|
return Container(
|
||||||
|
@ -8,6 +8,7 @@ skip_pub_get=false
|
|||||||
skip_pub_packages_get=false
|
skip_pub_packages_get=false
|
||||||
verbose=false
|
verbose=false
|
||||||
exclude_packages=false
|
exclude_packages=false
|
||||||
|
show_loading=false
|
||||||
|
|
||||||
# Parse command line arguments
|
# Parse command line arguments
|
||||||
while [[ $# -gt 0 ]]; do
|
while [[ $# -gt 0 ]]; do
|
||||||
@ -28,6 +29,10 @@ while [[ $# -gt 0 ]]; do
|
|||||||
exclude_packages=true
|
exclude_packages=true
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
--show-loading)
|
||||||
|
show_loading=true
|
||||||
|
shift
|
||||||
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown option: $1"
|
echo "Unknown option: $1"
|
||||||
exit 1
|
exit 1
|
||||||
@ -111,11 +116,13 @@ fi
|
|||||||
# Get the PID of the background process
|
# Get the PID of the background process
|
||||||
build_pid=$!
|
build_pid=$!
|
||||||
|
|
||||||
# Start the loading animation
|
if [ "$show_loading" = true ]; then
|
||||||
display_loading $build_pid &
|
# Start the loading animation
|
||||||
|
display_loading $build_pid &
|
||||||
|
|
||||||
# Get the PID of the loading animation
|
# Get the PID of the loading animation
|
||||||
loading_pid=$!
|
loading_pid=$!
|
||||||
|
fi
|
||||||
|
|
||||||
# Wait for the build_runner to finish
|
# Wait for the build_runner to finish
|
||||||
wait $build_pid
|
wait $build_pid
|
||||||
|
@ -64,7 +64,7 @@ cd ..
|
|||||||
cd freezed
|
cd freezed
|
||||||
# Allow execution permissions on CI
|
# Allow execution permissions on CI
|
||||||
chmod +x ./generate_freezed.sh
|
chmod +x ./generate_freezed.sh
|
||||||
./generate_freezed.sh "${args[@]}"
|
./generate_freezed.sh "${args[@]}" --show-loading
|
||||||
|
|
||||||
# Return to the original directory
|
# Return to the original directory
|
||||||
cd "$original_dir"
|
cd "$original_dir"
|
||||||
|
Loading…
Reference in New Issue
Block a user