mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
chore: improve UI design on mobile (#5816)
This commit is contained in:
parent
22b108df70
commit
ddf68b010d
@ -175,7 +175,7 @@ SPEC CHECKSUMS:
|
||||
file_picker: 09aa5ec1ab24135ccd7a1621c46c84134bfd6655
|
||||
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
|
||||
Flutter: e0871f40cf51350855a761d2e70bf5af5b9b5de7
|
||||
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
|
||||
fluttertoast: e9a18c7be5413da53898f660530c56f35edfba9c
|
||||
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
|
||||
image_picker_ios: 99dfe1854b4fa34d0364e74a78448a0151025425
|
||||
integration_test: ce0a3ffa1de96d1a89ca0ac26fca7ea18a749ef4
|
||||
|
@ -23,6 +23,9 @@ class DocumentPageStyleBloc
|
||||
await event.when(
|
||||
initial: () async {
|
||||
try {
|
||||
if (view.id.isEmpty) {
|
||||
return;
|
||||
}
|
||||
final layoutObject =
|
||||
await ViewBackendService.getView(view.id).fold(
|
||||
(s) => jsonDecode(s.extra),
|
||||
|
@ -0,0 +1,54 @@
|
||||
import 'package:appflowy/shared/feedback_gesture_detector.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class AnimatedGestureDetector extends StatefulWidget {
|
||||
const AnimatedGestureDetector({
|
||||
super.key,
|
||||
this.scaleFactor = 0.98,
|
||||
this.feedback = true,
|
||||
this.duration = const Duration(milliseconds: 100),
|
||||
this.alignment = Alignment.center,
|
||||
this.behavior = HitTestBehavior.opaque,
|
||||
required this.onTapUp,
|
||||
required this.child,
|
||||
});
|
||||
|
||||
final Widget child;
|
||||
final double scaleFactor;
|
||||
final Duration duration;
|
||||
final Alignment alignment;
|
||||
final bool feedback;
|
||||
final HitTestBehavior behavior;
|
||||
final VoidCallback onTapUp;
|
||||
|
||||
@override
|
||||
State<AnimatedGestureDetector> createState() =>
|
||||
_AnimatedGestureDetectorState();
|
||||
}
|
||||
|
||||
class _AnimatedGestureDetectorState extends State<AnimatedGestureDetector> {
|
||||
double scale = 1.0;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return GestureDetector(
|
||||
behavior: widget.behavior,
|
||||
onTapUp: (details) {
|
||||
setState(() => scale = 1.0);
|
||||
|
||||
HapticFeedbackType.vibrate.call();
|
||||
|
||||
widget.onTapUp();
|
||||
},
|
||||
onTapDown: (details) {
|
||||
setState(() => scale = widget.scaleFactor);
|
||||
},
|
||||
child: AnimatedScale(
|
||||
scale: scale,
|
||||
alignment: widget.alignment,
|
||||
duration: widget.duration,
|
||||
child: widget.child,
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
@ -24,9 +24,10 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
|
||||
height: 52.0,
|
||||
leftIcon: const FlowySvg(
|
||||
FlowySvgs.icon_document_s,
|
||||
size: Size.square(18),
|
||||
size: Size.square(20),
|
||||
),
|
||||
showTopBorder: false,
|
||||
showBottomBorder: false,
|
||||
onTap: () => onAction(ViewLayoutPB.Document),
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
@ -34,9 +35,10 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
|
||||
height: 52.0,
|
||||
leftIcon: const FlowySvg(
|
||||
FlowySvgs.icon_grid_s,
|
||||
size: Size.square(18),
|
||||
size: Size.square(20),
|
||||
),
|
||||
showTopBorder: false,
|
||||
showBottomBorder: false,
|
||||
onTap: () => onAction(ViewLayoutPB.Grid),
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
@ -44,9 +46,10 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
|
||||
height: 52.0,
|
||||
leftIcon: const FlowySvg(
|
||||
FlowySvgs.icon_board_s,
|
||||
size: Size.square(18),
|
||||
size: Size.square(20),
|
||||
),
|
||||
showTopBorder: false,
|
||||
showBottomBorder: false,
|
||||
onTap: () => onAction(ViewLayoutPB.Board),
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
@ -54,9 +57,10 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
|
||||
height: 52.0,
|
||||
leftIcon: const FlowySvg(
|
||||
FlowySvgs.icon_calendar_s,
|
||||
size: Size.square(18),
|
||||
size: Size.square(20),
|
||||
),
|
||||
showTopBorder: false,
|
||||
showBottomBorder: false,
|
||||
onTap: () => onAction(ViewLayoutPB.Calendar),
|
||||
),
|
||||
FlowyOptionTile.text(
|
||||
@ -64,9 +68,10 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
|
||||
height: 52.0,
|
||||
leftIcon: const FlowySvg(
|
||||
FlowySvgs.chat_ai_page_s,
|
||||
size: Size.square(18),
|
||||
size: Size.square(20),
|
||||
),
|
||||
showTopBorder: false,
|
||||
showBottomBorder: false,
|
||||
onTap: () => onAction(ViewLayoutPB.Chat),
|
||||
),
|
||||
],
|
||||
|
@ -1,4 +1,3 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_confirm_dialog.dart';
|
||||
@ -6,6 +5,7 @@ import 'package:appflowy/startup/tasks/app_widget.dart';
|
||||
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -109,16 +109,6 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
|
||||
await _showConfirmDialog(
|
||||
onDelete: () {
|
||||
recentViewsBloc.add(RecentViewsEvent.removeRecentViews([viewId]));
|
||||
|
||||
fToast.showToast(
|
||||
child: const _RemoveToast(),
|
||||
positionedToastBuilder: (context, child) {
|
||||
return Positioned.fill(
|
||||
top: 450,
|
||||
child: child,
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
@ -136,38 +126,14 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
|
||||
),
|
||||
onRightButtonPressed: (context) {
|
||||
onDelete();
|
||||
|
||||
Navigator.pop(context);
|
||||
|
||||
showToastNotification(
|
||||
context,
|
||||
message: LocaleKeys.sideBar_removeSuccess.tr(),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _RemoveToast extends StatelessWidget {
|
||||
const _RemoveToast();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return 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: [
|
||||
const FlowySvg(
|
||||
FlowySvgs.success_s,
|
||||
blendMode: null,
|
||||
),
|
||||
const HSpace(8.0),
|
||||
FlowyText.regular(
|
||||
LocaleKeys.sideBar_removeSuccess.tr(),
|
||||
fontSize: 16.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -7,6 +7,7 @@ import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/recent/recent_views_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/widgets/dialogs.dart';
|
||||
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';
|
||||
@ -40,18 +41,32 @@ enum MobilePaneActionType {
|
||||
backgroundColor: const Color(0xFFFA217F),
|
||||
svg: FlowySvgs.favorite_section_remove_from_favorite_s,
|
||||
size: 24.0,
|
||||
onPressed: (context) => context
|
||||
.read<FavoriteBloc>()
|
||||
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view)),
|
||||
onPressed: (context) {
|
||||
showToastNotification(
|
||||
context,
|
||||
message: LocaleKeys.button_unfavoriteSuccessfully.tr(),
|
||||
);
|
||||
|
||||
context
|
||||
.read<FavoriteBloc>()
|
||||
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view));
|
||||
},
|
||||
);
|
||||
case MobilePaneActionType.addToFavorites:
|
||||
return MobileSlideActionButton(
|
||||
backgroundColor: const Color(0xFF00C8FF),
|
||||
svg: FlowySvgs.favorite_s,
|
||||
size: 24.0,
|
||||
onPressed: (context) => context
|
||||
.read<FavoriteBloc>()
|
||||
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view)),
|
||||
onPressed: (context) {
|
||||
showToastNotification(
|
||||
context,
|
||||
message: LocaleKeys.button_favoriteSuccessfully.tr(),
|
||||
);
|
||||
|
||||
context
|
||||
.read<FavoriteBloc>()
|
||||
.add(FavoriteEvent.toggle(context.read<ViewBloc>().view));
|
||||
},
|
||||
);
|
||||
case MobilePaneActionType.add:
|
||||
return MobileSlideActionButton(
|
||||
@ -69,6 +84,7 @@ enum MobilePaneActionType {
|
||||
showDragHandle: true,
|
||||
showCloseButton: true,
|
||||
useRootNavigator: true,
|
||||
showDivider: false,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
builder: (sheetContext) {
|
||||
return AddNewPageWidgetBottomSheet(
|
||||
@ -145,8 +161,6 @@ enum MobilePaneActionType {
|
||||
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
|
||||
: MobileViewItemBottomSheetBodyAction.addToFavorites,
|
||||
MobileViewItemBottomSheetBodyAction.divider,
|
||||
if (view.layout != ViewLayoutPB.Chat)
|
||||
MobileViewItemBottomSheetBodyAction.duplicate,
|
||||
MobileViewItemBottomSheetBodyAction.divider,
|
||||
MobileViewItemBottomSheetBodyAction.removeFromRecent,
|
||||
];
|
||||
@ -156,7 +170,6 @@ enum MobilePaneActionType {
|
||||
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
|
||||
: MobileViewItemBottomSheetBodyAction.addToFavorites,
|
||||
MobileViewItemBottomSheetBodyAction.divider,
|
||||
MobileViewItemBottomSheetBodyAction.duplicate,
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -181,12 +194,13 @@ ActionPane buildEndActionPane(
|
||||
bool needSpace = true,
|
||||
MobilePageCardType? cardType,
|
||||
FolderSpaceType? spaceType,
|
||||
required double spaceRatio,
|
||||
}) {
|
||||
return ActionPane(
|
||||
motion: const ScrollMotion(),
|
||||
extentRatio: actions.length / 5,
|
||||
extentRatio: actions.length / spaceRatio,
|
||||
children: [
|
||||
if (needSpace) const HSpace(20),
|
||||
if (needSpace) const HSpace(60),
|
||||
...actions.map(
|
||||
(action) => action.actionButton(
|
||||
context,
|
||||
|
@ -70,6 +70,7 @@ Future<T?> showMobileBottomSheet<T>(
|
||||
backgroundColor ??= Theme.of(context).brightness == Brightness.light
|
||||
? const Color(0xFFF7F8FB)
|
||||
: const Color(0xFF23262B);
|
||||
barrierColor ??= Colors.black.withOpacity(0.3);
|
||||
|
||||
return showModalBottomSheet<T>(
|
||||
context: context,
|
||||
@ -226,10 +227,14 @@ class BottomSheetHeader extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
Align(
|
||||
child: FlowyText(
|
||||
title,
|
||||
fontSize: 16.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
child: Container(
|
||||
constraints: const BoxConstraints(maxWidth: 250),
|
||||
child: FlowyText(
|
||||
title,
|
||||
fontSize: 17.0,
|
||||
fontWeight: FontWeight.w500,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
),
|
||||
if (showDoneButton)
|
||||
|
@ -100,8 +100,6 @@ class _FavoriteViews extends StatelessWidget {
|
||||
child: ListView.separated(
|
||||
key: const PageStorageKey('favorite_views_page_storage_key'),
|
||||
padding: EdgeInsets.only(
|
||||
left: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
right: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||
MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
|
@ -72,6 +72,7 @@ class MobileFavoriteFolder extends StatelessWidget {
|
||||
MobilePaneActionType.more,
|
||||
],
|
||||
spaceType: FolderSpaceType.favorite,
|
||||
spaceRatio: 5,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
@ -29,8 +29,6 @@ class _MobileHomeSpaceState extends State<MobileHomeSpace>
|
||||
child: SingleChildScrollView(
|
||||
child: Padding(
|
||||
padding: EdgeInsets.only(
|
||||
left: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
right: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
top: HomeSpaceViewSizes.mVerticalPadding,
|
||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||
MediaQuery.of(context).padding.bottom,
|
||||
|
@ -9,6 +9,7 @@ import 'package:appflowy/workspace/application/menu/sidebar_sections_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/sidebar/space/space_bloc.dart';
|
||||
import 'package:appflowy/workspace/application/user/user_workspace_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -91,7 +92,12 @@ class MobileFolders extends StatelessWidget {
|
||||
children: [
|
||||
..._buildSpaceOrSection(context, state),
|
||||
const VSpace(4.0),
|
||||
const _TrashButton(),
|
||||
const Padding(
|
||||
padding: EdgeInsets.symmetric(
|
||||
horizontal: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
),
|
||||
child: _TrashButton(),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
@ -1,5 +1,6 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/gesture.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/mobile/presentation/home/mobile_home_setting_page.dart';
|
||||
import 'package:appflowy/mobile/presentation/home/workspaces/workspace_menu_bottom_sheet.dart';
|
||||
@ -113,8 +114,9 @@ class _MobileWorkspace extends StatelessWidget {
|
||||
if (currentWorkspace == null) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
return GestureDetector(
|
||||
onTap: () {
|
||||
return AnimatedGestureDetector(
|
||||
alignment: Alignment.centerLeft,
|
||||
onTapUp: () {
|
||||
context.read<UserWorkspaceBloc>().add(
|
||||
const UserWorkspaceEvent.fetchWorkspaces(),
|
||||
);
|
||||
@ -143,7 +145,7 @@ class _MobileWorkspace extends StatelessWidget {
|
||||
: const HSpace(8),
|
||||
FlowyText.semibold(
|
||||
currentWorkspace.name,
|
||||
fontSize: 16.0,
|
||||
fontSize: 20.0,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
],
|
||||
@ -162,9 +164,10 @@ class _MobileWorkspace extends StatelessWidget {
|
||||
showHeader: true,
|
||||
showDragHandle: true,
|
||||
showCloseButton: true,
|
||||
useRootNavigator: true,
|
||||
title: LocaleKeys.workspace_menuTitle.tr(),
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
builder: (_) {
|
||||
builder: (sheetContext) {
|
||||
return BlocProvider.value(
|
||||
value: context.read<UserWorkspaceBloc>(),
|
||||
child: BlocBuilder<UserWorkspaceBloc, UserWorkspaceState>(
|
||||
@ -179,7 +182,7 @@ class _MobileWorkspace extends StatelessWidget {
|
||||
currentWorkspace: currentWorkspace,
|
||||
workspaces: workspaces,
|
||||
onWorkspaceSelected: (workspace) {
|
||||
context.pop();
|
||||
Navigator.of(sheetContext).pop();
|
||||
|
||||
if (workspace == currentWorkspace) {
|
||||
return;
|
||||
|
@ -72,8 +72,6 @@ class _RecentViews extends StatelessWidget {
|
||||
child: ListView.separated(
|
||||
key: const PageStorageKey('recent_views_page_storage_key'),
|
||||
padding: EdgeInsets.only(
|
||||
left: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
right: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
bottom: HomeSpaceViewSizes.mVerticalPadding +
|
||||
MediaQuery.of(context).padding.bottom,
|
||||
),
|
||||
|
@ -82,6 +82,7 @@ class MobileSectionFolder extends StatelessWidget {
|
||||
],
|
||||
spaceType: spaceType,
|
||||
needSpace: false,
|
||||
spaceRatio: 5,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -5,6 +5,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||
import 'package:appflowy/mobile/application/recent/recent_view_bloc.dart';
|
||||
import 'package:appflowy/mobile/presentation/base/gesture.dart';
|
||||
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/shared/appflowy_network_image.dart';
|
||||
@ -15,6 +16,7 @@ import 'package:appflowy/workspace/application/settings/appearance/appearance_cu
|
||||
import 'package:appflowy/workspace/application/settings/date_time/date_format_ext.dart';
|
||||
import 'package:appflowy/workspace/application/settings/date_time/time_format_ext.dart';
|
||||
import 'package:appflowy/workspace/application/view/view_bloc.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
@ -76,13 +78,14 @@ class MobileViewPage extends StatelessWidget {
|
||||
: MobilePaneActionType.addToFavorites,
|
||||
],
|
||||
cardType: type,
|
||||
spaceRatio: 4,
|
||||
),
|
||||
child: GestureDetector(
|
||||
behavior: HitTestBehavior.opaque,
|
||||
onTapUp: (_) => context.pushView(view),
|
||||
child: AnimatedGestureDetector(
|
||||
onTapUp: () => context.pushView(view),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const HSpace(HomeSpaceViewSizes.mHorizontalPadding),
|
||||
Expanded(child: _buildDescription(context, state)),
|
||||
const HSpace(20.0),
|
||||
SizedBox(
|
||||
@ -90,6 +93,7 @@ class MobileViewPage extends StatelessWidget {
|
||||
height: 60,
|
||||
child: _buildCover(context, state),
|
||||
),
|
||||
const HSpace(HomeSpaceViewSizes.mHorizontalPadding),
|
||||
],
|
||||
),
|
||||
),
|
||||
@ -211,7 +215,7 @@ class MobileViewPage extends StatelessWidget {
|
||||
|
||||
Widget _buildLastViewed(BuildContext context) {
|
||||
final textColor = Theme.of(context).isLightMode
|
||||
? const Color(0xFF171717)
|
||||
? const Color(0x7F171717)
|
||||
: Colors.white.withOpacity(0.45);
|
||||
if (timestamp == null) {
|
||||
return const SizedBox.shrink();
|
||||
|
@ -50,23 +50,17 @@ class _MobileSpaceState extends State<MobileSpace> {
|
||||
MobileSpaceHeader(
|
||||
isExpanded: state.isExpanded,
|
||||
space: currentSpace,
|
||||
onAdded: () {
|
||||
context.read<SpaceBloc>().add(
|
||||
SpaceEvent.createPage(
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layout: ViewLayoutPB.Document,
|
||||
index: 0,
|
||||
),
|
||||
);
|
||||
context.read<SpaceBloc>().add(
|
||||
SpaceEvent.expand(currentSpace, true),
|
||||
);
|
||||
},
|
||||
onAdded: () => _showCreatePageMenu(currentSpace),
|
||||
onPressed: () => _showSpaceMenu(context),
|
||||
),
|
||||
_Pages(
|
||||
key: ValueKey(currentSpace.id),
|
||||
space: currentSpace,
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(
|
||||
left: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
),
|
||||
child: _Pages(
|
||||
key: ValueKey(currentSpace.id),
|
||||
space: currentSpace,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
@ -82,6 +76,7 @@ class _MobileSpaceState extends State<MobileSpace> {
|
||||
showDragHandle: true,
|
||||
showCloseButton: true,
|
||||
showDoneButton: true,
|
||||
useRootNavigator: true,
|
||||
title: LocaleKeys.space_title.tr(),
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
builder: (_) {
|
||||
@ -104,6 +99,38 @@ class _MobileSpaceState extends State<MobileSpace> {
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
void _showCreatePageMenu(ViewPB space) {
|
||||
final title = space.name;
|
||||
showMobileBottomSheet(
|
||||
context,
|
||||
showHeader: true,
|
||||
title: title,
|
||||
showDragHandle: true,
|
||||
showCloseButton: true,
|
||||
useRootNavigator: true,
|
||||
showDivider: false,
|
||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
||||
builder: (sheetContext) {
|
||||
return AddNewPageWidgetBottomSheet(
|
||||
view: space,
|
||||
onAction: (layout) {
|
||||
Navigator.of(sheetContext).pop();
|
||||
context.read<SpaceBloc>().add(
|
||||
SpaceEvent.createPage(
|
||||
name: LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
|
||||
layout: layout,
|
||||
index: 0,
|
||||
),
|
||||
);
|
||||
context.read<SpaceBloc>().add(
|
||||
SpaceEvent.expand(space, true),
|
||||
);
|
||||
},
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
class _Pages extends StatelessWidget {
|
||||
@ -148,7 +175,7 @@ class _Pages extends StatelessWidget {
|
||||
MobilePaneActionType.add,
|
||||
],
|
||||
spaceType: spaceType,
|
||||
needSpace: false,
|
||||
spaceRatio: 4,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -1,4 +1,5 @@
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/space_icon.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
@ -30,6 +31,7 @@ class MobileSpaceHeader extends StatelessWidget {
|
||||
height: 48,
|
||||
child: Row(
|
||||
children: [
|
||||
const HSpace(HomeSpaceViewSizes.mHorizontalPadding),
|
||||
SpaceIcon(
|
||||
dimension: 24,
|
||||
space: space,
|
||||
@ -49,8 +51,15 @@ class MobileSpaceHeader extends StatelessWidget {
|
||||
GestureDetector(
|
||||
behavior: HitTestBehavior.translucent,
|
||||
onTap: onAdded,
|
||||
child: const FlowySvg(
|
||||
FlowySvgs.m_space_add_s,
|
||||
child: Container(
|
||||
// expand the touch area
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: HomeSpaceViewSizes.mHorizontalPadding,
|
||||
vertical: 8.0,
|
||||
),
|
||||
child: const FlowySvg(
|
||||
FlowySvgs.m_space_add_s,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
@ -59,6 +59,7 @@ class _SidebarSpaceMenuItem extends StatelessWidget {
|
||||
children: [
|
||||
FlowyText.medium(
|
||||
space.name,
|
||||
fontSize: 16.0,
|
||||
),
|
||||
const HSpace(6.0),
|
||||
if (space.spacePermission == SpacePermission.private)
|
||||
@ -68,16 +69,17 @@ class _SidebarSpaceMenuItem extends StatelessWidget {
|
||||
),
|
||||
],
|
||||
),
|
||||
margin: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||
iconPadding: 10,
|
||||
leftIcon: SpaceIcon(
|
||||
dimension: 24,
|
||||
space: space,
|
||||
cornerRadius: 6.0,
|
||||
),
|
||||
leftIconSize: const Size.square(20),
|
||||
leftIconSize: const Size.square(24),
|
||||
rightIcon: isSelected
|
||||
? const FlowySvg(
|
||||
FlowySvgs.workspace_selected_s,
|
||||
FlowySvgs.m_blue_check_s,
|
||||
blendMode: null,
|
||||
)
|
||||
: null,
|
||||
|
@ -138,17 +138,20 @@ class _WorkspaceMenuItem extends StatelessWidget {
|
||||
height: 60,
|
||||
showTopBorder: showTopBorder,
|
||||
showBottomBorder: false,
|
||||
leftIcon: WorkspaceIcon(
|
||||
enableEdit: false,
|
||||
iconSize: 26,
|
||||
fontSize: 16.0,
|
||||
workspace: workspace,
|
||||
onSelected: (result) => context.read<UserWorkspaceBloc>().add(
|
||||
UserWorkspaceEvent.updateWorkspaceIcon(
|
||||
workspace.workspaceId,
|
||||
result.emoji,
|
||||
leftIcon: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4.0),
|
||||
child: WorkspaceIcon(
|
||||
enableEdit: false,
|
||||
iconSize: 26,
|
||||
fontSize: 16.0,
|
||||
workspace: workspace,
|
||||
onSelected: (result) => context.read<UserWorkspaceBloc>().add(
|
||||
UserWorkspaceEvent.updateWorkspaceIcon(
|
||||
workspace.workspaceId,
|
||||
result.emoji,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
trailing: workspace.workspaceId == currentWorkspace.workspaceId
|
||||
? const FlowySvg(
|
||||
|
@ -50,6 +50,9 @@ class MobileBottomNavigationBar extends StatelessWidget {
|
||||
final backgroundColor = isLightMode
|
||||
? Colors.white.withOpacity(0.95)
|
||||
: const Color(0xFF23262B).withOpacity(0.95);
|
||||
final borderColor = isLightMode
|
||||
? const Color(0x141F2329)
|
||||
: const Color(0xFF23262B).withOpacity(0.5);
|
||||
return Scaffold(
|
||||
body: navigationShell,
|
||||
extendBody: true,
|
||||
@ -62,9 +65,7 @@ class MobileBottomNavigationBar extends StatelessWidget {
|
||||
child: DecoratedBox(
|
||||
decoration: BoxDecoration(
|
||||
border: isLightMode
|
||||
? Border(
|
||||
top: BorderSide(color: Theme.of(context).dividerColor),
|
||||
)
|
||||
? Border(top: BorderSide(color: borderColor))
|
||||
: null,
|
||||
color: backgroundColor,
|
||||
),
|
||||
|
@ -300,7 +300,7 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
|
||||
)
|
||||
: Opacity(
|
||||
opacity: 0.7,
|
||||
child: widget.view.defaultIcon(),
|
||||
child: widget.view.defaultIcon(size: const Size.square(18)),
|
||||
);
|
||||
return SizedBox(width: 18.0, child: icon);
|
||||
}
|
||||
|
@ -1,11 +1,14 @@
|
||||
import 'package:appflowy/mobile/application/page_style/document_page_style_bloc.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_plugins/plugins.dart';
|
||||
import 'package:appflowy/plugins/document/presentation/editor_style.dart';
|
||||
import 'package:appflowy/shared/markdown_to_document.dart';
|
||||
import 'package:appflowy/util/theme_extension.dart';
|
||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:flowy_infra/theme_extension.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:markdown_widget/markdown_widget.dart';
|
||||
|
||||
import 'selectable_highlight.dart';
|
||||
@ -30,7 +33,11 @@ class AIMarkdownText extends StatelessWidget {
|
||||
Widget build(BuildContext context) {
|
||||
switch (type) {
|
||||
case AIMarkdownType.appflowyEditor:
|
||||
return _AppFlowyEditorMarkdown(markdown: markdown);
|
||||
return BlocProvider(
|
||||
create: (context) => DocumentPageStyleBloc(view: ViewPB())
|
||||
..add(const DocumentPageStyleEvent.initial()),
|
||||
child: _AppFlowyEditorMarkdown(markdown: markdown),
|
||||
);
|
||||
case AIMarkdownType.markdownWidget:
|
||||
return _ThirdPartyMarkdown(markdown: markdown);
|
||||
}
|
||||
|
@ -90,19 +90,22 @@ class _DocumentImmersiveCoverState extends State<DocumentImmersiveCover> {
|
||||
);
|
||||
}
|
||||
|
||||
return Stack(
|
||||
children: [
|
||||
_buildCover(context, state),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
||||
child: iconAndTitle,
|
||||
return Padding(
|
||||
padding: const EdgeInsets.only(bottom: 16),
|
||||
child: Stack(
|
||||
children: [
|
||||
_buildCover(context, state),
|
||||
Positioned(
|
||||
left: 0,
|
||||
right: 0,
|
||||
bottom: 0,
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(vertical: 24.0),
|
||||
child: iconAndTitle,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -4,7 +4,6 @@ import 'package:appflowy/core/config/kv.dart';
|
||||
import 'package:appflowy/core/config/kv_keys.dart';
|
||||
import 'package:appflowy/startup/startup.dart';
|
||||
import 'package:collection/collection.dart';
|
||||
import 'package:flutter/foundation.dart';
|
||||
|
||||
typedef FeatureFlagMap = Map<FeatureFlag, bool>;
|
||||
|
||||
|
@ -1,8 +1,5 @@
|
||||
import 'dart:io';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
|
||||
import 'package:appflowy/mobile/application/mobile_router.dart';
|
||||
import 'package:appflowy/plugins/document/application/document_appearance_cubit.dart';
|
||||
import 'package:appflowy/shared/feature_flags.dart';
|
||||
@ -24,8 +21,11 @@ import 'package:appflowy_editor/appflowy_editor.dart' hide Log;
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/theme.dart';
|
||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/services.dart';
|
||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||
import 'package:go_router/go_router.dart';
|
||||
import 'package:toastification/toastification.dart';
|
||||
|
||||
import 'prelude.dart';
|
||||
|
||||
@ -197,31 +197,33 @@ class _ApplicationWidgetState extends State<ApplicationWidget> {
|
||||
child: BlocBuilder<AppearanceSettingsCubit, AppearanceSettingsState>(
|
||||
builder: (context, state) {
|
||||
_setSystemOverlayStyle(state);
|
||||
return MaterialApp.router(
|
||||
builder: (context, child) => MediaQuery(
|
||||
// use the 1.0 as the textScaleFactor to avoid the text size
|
||||
// affected by the system setting.
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(state.textScaleFactor),
|
||||
),
|
||||
child: overlayManagerBuilder(
|
||||
context,
|
||||
!PlatformExtension.isMobile && FeatureFlag.search.isOn
|
||||
? CommandPalette(
|
||||
notifier: _commandPaletteNotifier,
|
||||
child: child,
|
||||
)
|
||||
: child,
|
||||
return ToastificationWrapper(
|
||||
child: MaterialApp.router(
|
||||
builder: (context, child) => MediaQuery(
|
||||
// use the 1.0 as the textScaleFactor to avoid the text size
|
||||
// affected by the system setting.
|
||||
data: MediaQuery.of(context).copyWith(
|
||||
textScaler: TextScaler.linear(state.textScaleFactor),
|
||||
),
|
||||
child: overlayManagerBuilder(
|
||||
context,
|
||||
!PlatformExtension.isMobile && FeatureFlag.search.isOn
|
||||
? CommandPalette(
|
||||
notifier: _commandPaletteNotifier,
|
||||
child: child,
|
||||
)
|
||||
: child,
|
||||
),
|
||||
),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: state.lightTheme,
|
||||
darkTheme: state.darkTheme,
|
||||
themeMode: state.themeMode,
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: state.locale,
|
||||
routerConfig: routerConfig,
|
||||
),
|
||||
debugShowCheckedModeBanner: false,
|
||||
theme: state.lightTheme,
|
||||
darkTheme: state.darkTheme,
|
||||
themeMode: state.themeMode,
|
||||
localizationsDelegates: context.localizationDelegates,
|
||||
supportedLocales: context.supportedLocales,
|
||||
locale: state.locale,
|
||||
routerConfig: routerConfig,
|
||||
);
|
||||
},
|
||||
),
|
||||
|
@ -48,7 +48,7 @@ class ViewExtKeys {
|
||||
}
|
||||
|
||||
extension ViewExtension on ViewPB {
|
||||
Widget defaultIcon() => FlowySvg(
|
||||
Widget defaultIcon({Size? size}) => FlowySvg(
|
||||
switch (layout) {
|
||||
ViewLayoutPB.Board => FlowySvgs.icon_board_s,
|
||||
ViewLayoutPB.Calendar => FlowySvgs.icon_calendar_s,
|
||||
@ -57,6 +57,7 @@ extension ViewExtension on ViewPB {
|
||||
ViewLayoutPB.Chat => FlowySvgs.chat_ai_page_s,
|
||||
_ => FlowySvgs.document_s,
|
||||
},
|
||||
size: size,
|
||||
);
|
||||
|
||||
PluginType get pluginType => switch (layout) {
|
||||
|
@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
import 'package:appflowy/generated/flowy_svgs.g.dart';
|
||||
import 'package:appflowy/generated/locale_keys.g.dart';
|
||||
import 'package:appflowy/startup/tasks/app_widget.dart';
|
||||
import 'package:appflowy/workspace/presentation/home/menu/sidebar/space/shared_widget.dart';
|
||||
import 'package:appflowy_editor/appflowy_editor.dart';
|
||||
import 'package:easy_localization/easy_localization.dart';
|
||||
import 'package:flowy_infra/size.dart';
|
||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||
@ -11,6 +11,7 @@ import 'package:flowy_infra_ui/widget/buttons/primary_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/buttons/secondary_button.dart';
|
||||
import 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
|
||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:toastification/toastification.dart';
|
||||
|
||||
export 'package:flowy_infra_ui/widget/dialog/styled_dialogs.dart';
|
||||
@ -303,6 +304,18 @@ void showToastNotification(
|
||||
String? description,
|
||||
ToastificationType type = ToastificationType.success,
|
||||
}) {
|
||||
if (PlatformExtension.isMobile) {
|
||||
toastification.showCustom(
|
||||
alignment: Alignment.bottomCenter,
|
||||
autoCloseDuration: const Duration(milliseconds: 3000),
|
||||
builder: (_, __) => _MToast(
|
||||
message: message,
|
||||
type: type,
|
||||
),
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
toastification.show(
|
||||
context: context,
|
||||
type: type,
|
||||
@ -329,6 +342,50 @@ void showToastNotification(
|
||||
);
|
||||
}
|
||||
|
||||
class _MToast extends StatelessWidget {
|
||||
const _MToast({
|
||||
required this.message,
|
||||
this.type = ToastificationType.success,
|
||||
});
|
||||
|
||||
final String message;
|
||||
final ToastificationType type;
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
// only support success type
|
||||
assert(type == ToastificationType.success);
|
||||
|
||||
return Container(
|
||||
alignment: Alignment.bottomCenter,
|
||||
padding: const EdgeInsets.only(bottom: 100),
|
||||
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: [
|
||||
const FlowySvg(
|
||||
FlowySvgs.success_s,
|
||||
blendMode: null,
|
||||
),
|
||||
const HSpace(8.0),
|
||||
FlowyText.regular(
|
||||
message,
|
||||
fontSize: 16.0,
|
||||
figmaLineHeight: 18.0,
|
||||
color: Colors.white,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> showConfirmDeletionDialog({
|
||||
required BuildContext context,
|
||||
required String name,
|
||||
|
@ -276,7 +276,7 @@
|
||||
"justNow": "just now",
|
||||
"minutesAgo": "{count} minutes ago",
|
||||
"lastViewed": "Last viewed",
|
||||
"favoriteAt": "Favorited at",
|
||||
"favoriteAt": "Favorited",
|
||||
"emptyRecent": "No Recent Documents",
|
||||
"emptyRecentDescription": "As you view documents, they will appear here for easy retrieval",
|
||||
"emptyFavorite": "No Favorite Documents",
|
||||
@ -337,6 +337,8 @@
|
||||
"removeFromFavorites": "Remove from favorites",
|
||||
"removeFromRecent": "Remove from recent",
|
||||
"addToFavorites": "Add to favorites",
|
||||
"favoriteSuccessfully": "Favorited success",
|
||||
"unfavoriteSuccessfully": "Unfavorited success",
|
||||
"rename": "Rename",
|
||||
"helpCenter": "Help Center",
|
||||
"add": "Add",
|
||||
|
Loading…
Reference in New Issue
Block a user