feat: action sheet revamp (#4497)

This commit is contained in:
Lucas.Xu 2024-01-26 00:33:45 +08:00 committed by GitHub
parent be00980fdd
commit 0e3ffa8fd5
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
31 changed files with 429 additions and 457 deletions

View File

@ -179,7 +179,7 @@ SPEC CHECKSUMS:
file_picker: 15fd9539e4eb735dc54bae8c0534a7a9511a03de
flowy_infra_ui: 0455e1fa8c51885aa1437848e361e99419f34ebc
Flutter: f04841e97a9d0b0a8025694d0796dd46242b2854
fluttertoast: 31b00dabfa7fb7bacd9e7dbee580d7a2ff4bf265
fluttertoast: fafc4fa4d01a6a9e4f772ecd190ffa525e9e2d9c
FMDB: 2ce00b547f966261cd18927a3ddb07cb6f3db82a
image_gallery_saver: cb43cc43141711190510e92c460eb1655cd343cb
image_picker_ios: 4a8aadfbb6dc30ad5141a2ce3832af9214a705b5
@ -202,4 +202,4 @@ SPEC CHECKSUMS:
PODFILE CHECKSUM: 8c681999c7764593c94846b2a64b44d86f7a27ac
COCOAPODS: 1.14.3
COCOAPODS: 1.12.1

View File

@ -65,6 +65,32 @@ class AppBarCancelButton extends StatelessWidget {
}
}
class AppBarDoneButton extends StatelessWidget {
const AppBarDoneButton({
super.key,
required this.onTap,
});
final VoidCallback onTap;
@override
Widget build(BuildContext context) {
return AppBarButton(
onTap: onTap,
extent: 0.0,
child: Padding(
padding: const EdgeInsets.only(right: 8.0),
child: FlowyText(
LocaleKeys.button_Done.tr(),
color: Theme.of(context).colorScheme.primary,
fontWeight: FontWeight.w500,
textAlign: TextAlign.right,
),
),
);
}
}
class AppBarMoreButton extends StatelessWidget {
const AppBarMoreButton({
super.key,

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@ -17,6 +15,7 @@ import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:dartz/dartz.dart' hide State;
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
@ -151,6 +150,10 @@ class _MobileViewPageState extends State<MobileViewPage> {
onTap: (context) {
showMobileBottomSheet(
context,
showDragHandle: true,
showDivider: false,
padding: const EdgeInsets.only(bottom: 36.0),
backgroundColor: Theme.of(context).colorScheme.background,
builder: (_) => _buildViewPageBottomSheet(context),
);
},

View File

@ -1,9 +1,8 @@
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_action_widget.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.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';
import 'package:flutter/material.dart';
class AddNewPageWidgetBottomSheet extends StatelessWidget {
@ -20,47 +19,41 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
Widget build(BuildContext context) {
return Column(
children: [
// new document, new grid
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.document_s,
text: LocaleKeys.document_menuName.tr(),
onTap: () => onAction(ViewLayoutPB.Document),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.grid_s,
text: LocaleKeys.grid_menuName.tr(),
onTap: () => onAction(ViewLayoutPB.Grid),
),
),
],
FlowyOptionTile.text(
text: LocaleKeys.document_menuName.tr(),
leftIcon: const FlowySvg(
FlowySvgs.document_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Document),
),
const VSpace(8),
// new board, new calendar
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.board_s,
text: LocaleKeys.board_menuName.tr(),
onTap: () => onAction(ViewLayoutPB.Board),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.date_s,
text: LocaleKeys.calendar_menuName.tr(),
onTap: () => onAction(ViewLayoutPB.Calendar),
),
),
],
FlowyOptionTile.text(
text: LocaleKeys.grid_menuName.tr(),
leftIcon: const FlowySvg(
FlowySvgs.grid_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Grid),
),
FlowyOptionTile.text(
text: LocaleKeys.board_menuName.tr(),
leftIcon: const FlowySvg(
FlowySvgs.board_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Board),
),
FlowyOptionTile.text(
text: LocaleKeys.calendar_menuName.tr(),
leftIcon: const FlowySvg(
FlowySvgs.date_s,
size: Size.square(20),
),
showTopBorder: false,
onTap: () => onAction(ViewLayoutPB.Calendar),
),
],
);

View File

@ -2,10 +2,8 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/protobuf.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart' hide WidgetBuilder;
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
enum MobileBottomSheetType {
view,
@ -39,36 +37,6 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// header
_buildHeader(),
const VSpace(16),
// body
_buildBody(),
],
);
}
Widget _buildHeader() {
switch (type) {
case MobileBottomSheetType.view:
case MobileBottomSheetType.rename:
// header
return MobileViewItemBottomSheetHeader(
showBackButton: type != MobileBottomSheetType.view,
view: widget.view,
onBack: () {
setState(() {
type = MobileBottomSheetType.view;
});
},
);
}
}
Widget _buildBody() {
switch (type) {
case MobileBottomSheetType.view:
return MobileViewItemBottomSheetBody(
@ -81,21 +49,21 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
});
break;
case MobileViewItemBottomSheetBodyAction.duplicate:
context.pop();
Navigator.pop(context);
context.read<ViewBloc>().add(const ViewEvent.duplicate());
break;
case MobileViewItemBottomSheetBodyAction.share:
// unimplemented
context.pop();
Navigator.pop(context);
break;
case MobileViewItemBottomSheetBodyAction.delete:
context.pop();
Navigator.pop(context);
context.read<ViewBloc>().add(const ViewEvent.delete());
break;
case MobileViewItemBottomSheetBodyAction.addToFavorites:
case MobileViewItemBottomSheetBodyAction.removeFromFavorites:
context.pop();
Navigator.pop(context);
context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(widget.view));
@ -110,7 +78,7 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
if (name != widget.view.name) {
context.read<ViewBloc>().add(ViewEvent.rename(name));
}
context.pop();
Navigator.pop(context);
},
);
}

View File

@ -1,8 +1,7 @@
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_action_widget.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
enum MobileViewItemBottomSheetBodyAction {
@ -29,74 +28,56 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// rename, duplicate
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_rename_m,
text: LocaleKeys.button_rename.tr(),
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.rename,
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_duplicate_m,
text: LocaleKeys.button_duplicate.tr(),
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.duplicate,
),
),
),
],
FlowyOptionTile.text(
text: LocaleKeys.button_rename.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_rename_s,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.rename,
),
),
const VSpace(8),
// share, delete
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_share_m,
text: LocaleKeys.button_share.tr(),
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.share,
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_delete_m,
text: LocaleKeys.button_delete.tr(),
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.delete,
),
),
),
],
),
const VSpace(8),
// remove from favorites/add to favorites
BottomSheetActionWidget(
svg: isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
//TODO(yijing): switch to theme color
iconColor: isFavorite ? Colors.yellow : null,
FlowyOptionTile.text(
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),
leftIcon: FlowySvg(
size: const Size(20, 20),
isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
color: isFavorite ? Colors.yellow : null,
),
showTopBorder: false,
onTap: () => onAction(
isFavorite
? MobileViewItemBottomSheetBodyAction.removeFromFavorites
: MobileViewItemBottomSheetBodyAction.addToFavorites,
),
),
FlowyOptionTile.text(
text: LocaleKeys.button_duplicate.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_duplicate_s,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.duplicate,
),
),
FlowyOptionTile.text(
text: LocaleKeys.button_delete.tr(),
textColor: Theme.of(context).colorScheme.error,
leftIcon: FlowySvg(
FlowySvgs.m_delete_s,
color: Theme.of(context).colorScheme.error,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewItemBottomSheetBodyAction.delete,
),
),
],
);
}

View File

@ -1,9 +1,9 @@
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/widgets.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';
import 'package:flutter/material.dart';
enum MobileViewBottomSheetBodyAction {
@ -43,36 +43,6 @@ class _ViewPageBottomSheetState extends State<ViewPageBottomSheet> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// header
_buildHeader(),
const VSpace(16),
// body
_buildBody(),
],
);
}
Widget _buildHeader() {
switch (type) {
case MobileBottomSheetType.view:
case MobileBottomSheetType.rename:
// header
return MobileViewItemBottomSheetHeader(
showBackButton: type != MobileBottomSheetType.view,
view: widget.view,
onBack: () {
setState(() {
type = MobileBottomSheetType.view;
});
},
);
}
}
Widget _buildBody() {
switch (type) {
case MobileBottomSheetType.view:
return MobileViewBottomSheetBody(
@ -117,84 +87,56 @@ class MobileViewBottomSheetBody extends StatelessWidget {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// rename, duplicate
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_rename_m,
text: LocaleKeys.button_rename.tr(),
onTap: () => onAction(
MobileViewBottomSheetBodyAction.rename,
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_duplicate_m,
text: LocaleKeys.button_duplicate.tr(),
onTap: () => onAction(
MobileViewBottomSheetBodyAction.duplicate,
),
),
),
],
FlowyOptionTile.text(
text: LocaleKeys.button_rename.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_rename_s,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.rename,
),
),
const VSpace(8),
// share, delete
Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_share_m,
text: LocaleKeys.button_share.tr(),
onTap: () => onAction(
MobileViewBottomSheetBodyAction.share,
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_delete_m,
text: LocaleKeys.button_delete.tr(),
onTap: () => onAction(
MobileViewBottomSheetBodyAction.delete,
),
),
),
],
),
const VSpace(8),
// favorites
BottomSheetActionWidget(
svg: isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
//TODO(yijing): switch to theme color
iconColor: isFavorite ? Colors.yellow : null,
FlowyOptionTile.text(
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),
leftIcon: FlowySvg(
size: const Size(20, 20),
isFavorite
? FlowySvgs.m_favorite_selected_lg
: FlowySvgs.m_favorite_unselected_lg,
color: isFavorite ? Colors.yellow : null,
),
showTopBorder: false,
onTap: () => onAction(
isFavorite
? MobileViewBottomSheetBodyAction.removeFromFavorites
: MobileViewBottomSheetBodyAction.addToFavorites,
),
),
// Help Center
// const VSpace(8),
// BottomSheetActionWidget(
// svg: FlowySvgs.m_help_center_m,
// text: LocaleKeys.button_helpCenter.tr(),
// onTap: () => onAction(
// MobileViewBottomSheetBodyAction.helpCenter,
// ),
// ),
FlowyOptionTile.text(
text: LocaleKeys.button_duplicate.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_duplicate_s,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.duplicate,
),
),
FlowyOptionTile.text(
text: LocaleKeys.button_delete.tr(),
textColor: Theme.of(context).colorScheme.error,
leftIcon: FlowySvg(
FlowySvgs.m_delete_s,
color: Theme.of(context).colorScheme.error,
),
showTopBorder: false,
onTap: () => onAction(
MobileViewBottomSheetBodyAction.delete,
),
),
],
);
}

View File

@ -52,6 +52,11 @@ enum MobilePaneActionType {
final favoriteBloc = context.read<FavoriteBloc>();
showMobileBottomSheet(
context,
showDragHandle: true,
showDivider: false,
padding: const EdgeInsets.only(bottom: 36.0),
backgroundColor: Theme.of(context).colorScheme.background,
useRootNavigator: true,
builder: (context) {
return MultiBlocProvider(
providers: [

View File

@ -7,26 +7,37 @@ import 'package:flutter/material.dart';
Future<T?> showMobileBottomSheet<T>(
BuildContext context, {
required WidgetBuilder builder,
ShapeBorder? shape,
bool isDragEnabled = true,
bool resizeToAvoidBottomInset = true,
EdgeInsets padding = const EdgeInsets.fromLTRB(16, 16, 16, 32),
bool showDragHandle = false,
bool showHeader = false,
// this field is only used if showHeader is true
bool showCloseButton = false,
String title = '', // only works if showHeader is true
Color? backgroundColor,
// this field is only used if showHeader is true
String title = '',
bool resizeToAvoidBottomInset = true,
bool isScrollControlled = true,
BoxConstraints? constraints,
bool showDivider = true,
bool useRootNavigator = false,
ShapeBorder? shape,
// the padding of the content, the padding of the header area is fixed
EdgeInsets padding = const EdgeInsets.fromLTRB(16, 4, 16, 32),
Color? backgroundColor,
BoxConstraints? constraints,
Color? barrierColor,
double? elevation,
bool showDoneButton = false,
}) async {
assert(() {
if (showCloseButton || title.isNotEmpty) assert(showHeader);
return true;
}());
shape ??= const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Corners.s12Radius,
),
);
return showModalBottomSheet<T>(
context: context,
isScrollControlled: isScrollControlled,
@ -37,68 +48,63 @@ Future<T?> showMobileBottomSheet<T>(
constraints: constraints,
barrierColor: barrierColor,
elevation: elevation,
shape: shape ??
const RoundedRectangleBorder(
borderRadius: BorderRadius.vertical(
top: Corners.s12Radius,
),
),
shape: shape,
useRootNavigator: useRootNavigator,
builder: (context) {
final List<Widget> children = [];
final child = builder(context);
// if the children is only one, we don't need to wrap it with a column
if (!showDragHandle &&
!showHeader &&
!showDivider &&
!resizeToAvoidBottomInset) {
return child;
}
// ----- header area -----
if (showDragHandle) {
children.addAll([
children.add(
const DragHandler(),
]);
);
}
if (showHeader) {
children.addAll([
VSpace(padding.top),
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
showCloseButton
? Padding(
padding: EdgeInsets.only(left: padding.left),
child: const AppBarCloseButton(
margin: EdgeInsets.zero,
),
)
: const SizedBox.shrink(),
FlowyText(
title,
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
showCloseButton
? HSpace(padding.right + 24)
: const SizedBox.shrink(),
],
children.add(
_Header(
showCloseButton: showCloseButton,
showDoneButton: showDoneButton,
title: title,
),
const VSpace(4),
if (showDivider) const Divider(),
]);
);
if (showDivider) {
children.add(
const Divider(height: 1.0, thickness: 1.0),
);
}
}
final child = builder(context);
// ----- header area -----
// ----- content area -----
if (resizeToAvoidBottomInset) {
children.add(
AnimatedPadding(
Padding(
padding: EdgeInsets.only(
top: showHeader ? 0 : padding.top,
top: padding.top,
left: padding.left,
right: padding.right,
bottom: padding.bottom + MediaQuery.of(context).viewInsets.bottom,
),
duration: Duration.zero,
child: child,
),
);
} else {
children.add(child);
}
// ----- content area -----
if (children.length == 1) {
return children.first;
@ -111,3 +117,56 @@ Future<T?> showMobileBottomSheet<T>(
},
);
}
class _Header extends StatelessWidget {
const _Header({
required this.showCloseButton,
required this.title,
required this.showDoneButton,
});
final bool showCloseButton;
final String title;
final bool showDoneButton;
@override
Widget build(BuildContext context) {
return Padding(
padding: const EdgeInsets.only(bottom: 4.0),
child: SizedBox(
height: 44.0, // the height of the header area is fixed
child: Stack(
children: [
if (showCloseButton)
const Align(
alignment: Alignment.centerLeft,
child: Padding(
padding: EdgeInsets.only(left: 16),
child: AppBarCloseButton(
margin: EdgeInsets.zero,
),
),
),
Align(
child: FlowyText(
title,
fontSize: 16.0,
fontWeight: FontWeight.w500,
),
),
if (showDoneButton)
Align(
alignment: Alignment.centerRight,
child: Padding(
padding: const EdgeInsets.only(right: 16),
child: AppBarDoneButton(
onTap: () => Navigator.pop(context),
),
),
),
],
),
),
);
}
}

View File

@ -30,8 +30,6 @@ class MobileDatabaseViewList extends StatelessWidget {
builder: (context, state) {
final views = [state.view, ...state.view.childViews];
final children = [
const Center(child: DragHandler()),
const _Header(),
...views.mapIndexed(
(index, view) => MobileDatabaseViewListButton(
view: view,
@ -50,38 +48,6 @@ class MobileDatabaseViewList extends StatelessWidget {
}
}
class _Header extends StatelessWidget {
const _Header();
@override
Widget build(BuildContext context) {
const iconWidth = 30.0;
return Padding(
padding: const EdgeInsets.fromLTRB(8, 4, 8, 12),
child: Stack(
children: [
Align(
alignment: Alignment.centerLeft,
child: FlowyIconButton(
icon: const FlowySvg(
FlowySvgs.close_s,
size: Size.square(iconWidth),
),
onPressed: () => context.pop(),
),
),
Align(
child: FlowyText.medium(
LocaleKeys.grid_settings_viewList.tr(),
fontSize: 16,
),
),
],
),
);
}
}
@visibleForTesting
class MobileDatabaseViewListButton extends StatelessWidget {
const MobileDatabaseViewListButton({
@ -141,6 +107,7 @@ class MobileDatabaseViewListButton extends StatelessWidget {
showMobileBottomSheet(
context,
padding: EdgeInsets.zero,
showDragHandle: true,
builder: (_) {
return BlocProvider<ViewBloc>(
create: (_) =>
@ -189,7 +156,7 @@ class MobileNewDatabaseViewButton extends StatelessWidget {
onTap: () async {
final result = await showMobileBottomSheet<(DatabaseLayoutPB, String)>(
context,
padding: EdgeInsets.zero,
padding: const EdgeInsets.only(bottom: 36),
builder: (_) {
return const MobileCreateDatabaseView();
},
@ -239,6 +206,7 @@ class _MobileCreateDatabaseViewState extends State<MobileCreateDatabaseView> {
textController: controller,
selectedLayout: layoutType,
),
const VSpace(4.0),
FlowyOptionTile.textField(
autofocus: true,
controller: controller,
@ -281,7 +249,7 @@ class _CreateViewHeader extends StatelessWidget {
onPressed: () => context.pop(),
icon: const FlowySvg(
FlowySvgs.arrow_left_s,
size: Size.square(20),
size: Size.square(24),
),
),
),

View File

@ -338,6 +338,7 @@ class DatabaseViewSettingTile extends StatelessWidget {
context,
padding: EdgeInsets.zero,
resizeToAvoidBottomInset: false,
showDragHandle: true,
builder: (context) {
return Padding(
padding: const EdgeInsets.only(top: 24, bottom: 46),

View File

@ -13,7 +13,6 @@ import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:flutter_slidable/flutter_slidable.dart';
import 'package:go_router/go_router.dart';
typedef ViewItemOnSelected = void Function(ViewPB);
typedef ActionPaneBuilder = ActionPane Function(BuildContext context);
@ -395,13 +394,15 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
context,
showHeader: true,
title: title,
showCloseButton: true,
showDragHandle: true,
builder: (_) {
showCloseButton: true,
useRootNavigator: true,
padding: const EdgeInsets.only(bottom: 36),
builder: (sheetContext) {
return AddNewPageWidgetBottomSheet(
view: widget.view,
onAction: (layout) {
context.pop();
Navigator.of(sheetContext).pop();
context.read<ViewBloc>().add(
ViewEvent.createView(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),

View File

@ -39,31 +39,28 @@ class RTLSetting extends StatelessWidget {
showDivider: false,
showCloseButton: false,
title: LocaleKeys.settings_appearance_textDirection_label.tr(),
padding: const EdgeInsets.fromLTRB(0, 8, 0, 48),
padding: const EdgeInsets.only(bottom: 36),
builder: (context) {
final layoutDirection =
context.watch<AppearanceSettingsCubit>().state.layoutDirection;
return Padding(
padding: const EdgeInsets.only(top: 10),
child: Column(
children: [
FlowyOptionTile.checkbox(
text: LocaleKeys.settings_appearance_textDirection_ltr.tr(),
isSelected: layoutDirection == LayoutDirection.ltrLayout,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setLayoutDirection(LayoutDirection.ltrLayout),
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_textDirection_rtl.tr(),
isSelected: layoutDirection == LayoutDirection.rtlLayout,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setLayoutDirection(LayoutDirection.rtlLayout),
),
],
),
return Column(
children: [
FlowyOptionTile.checkbox(
text: LocaleKeys.settings_appearance_textDirection_ltr.tr(),
isSelected: layoutDirection == LayoutDirection.ltrLayout,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setLayoutDirection(LayoutDirection.ltrLayout),
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_textDirection_rtl.tr(),
isSelected: layoutDirection == LayoutDirection.rtlLayout,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setLayoutDirection(LayoutDirection.rtlLayout),
),
],
);
},
);

View File

@ -1,3 +1,4 @@
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/widgets.dart';
@ -39,39 +40,45 @@ class ThemeSetting extends StatelessWidget {
showDivider: false,
showCloseButton: false,
title: LocaleKeys.settings_appearance_themeMode_label.tr(),
padding: const EdgeInsets.fromLTRB(0, 8, 0, 48),
padding: const EdgeInsets.only(bottom: 36),
builder: (context) {
final themeMode =
context.read<AppearanceSettingsCubit>().state.themeMode;
return Padding(
padding: const EdgeInsets.only(top: 10),
child: Column(
children: [
FlowyOptionTile.checkbox(
text: LocaleKeys.settings_appearance_themeMode_system.tr(),
isSelected: themeMode == ThemeMode.system,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.system),
return Column(
children: [
FlowyOptionTile.checkbox(
text: LocaleKeys.settings_appearance_themeMode_system.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_theme_mode_system_s,
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_themeMode_light.tr(),
isSelected: themeMode == ThemeMode.light,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.light),
isSelected: themeMode == ThemeMode.system,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.system),
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_themeMode_light.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_theme_mode_light_s,
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_themeMode_dark.tr(),
isSelected: themeMode == ThemeMode.dark,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.dark),
isSelected: themeMode == ThemeMode.light,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.light),
),
FlowyOptionTile.checkbox(
showTopBorder: false,
text: LocaleKeys.settings_appearance_themeMode_dark.tr(),
leftIcon: const FlowySvg(
FlowySvgs.m_theme_mode_dark_s,
),
],
),
isSelected: themeMode == ThemeMode.dark,
onTap: () => context
.read<AppearanceSettingsCubit>()
.setThemeMode(ThemeMode.dark),
),
],
);
},
);

View File

@ -1,5 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
@ -36,8 +37,6 @@ class _EditUsernameBottomSheetState extends State<EditUsernameBottomSheet> {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
void submitUserName() {
if (_formKey.currentState!.validate()) {
final value = _textFieldController.text;
@ -49,27 +48,6 @@ class _EditUsernameBottomSheetState extends State<EditUsernameBottomSheet> {
return Column(
mainAxisSize: MainAxisSize.min,
children: <Widget>[
Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
Text(
LocaleKeys.settings_mobile_username.tr(),
style: theme.textTheme.labelSmall,
),
IconButton(
icon: Icon(
Icons.close,
color: theme.hintColor,
),
onPressed: () {
widget.context.pop();
},
),
],
),
const SizedBox(
height: 16,
),
Form(
key: _formKey,
child: TextFormField(
@ -84,9 +62,7 @@ class _EditUsernameBottomSheetState extends State<EditUsernameBottomSheet> {
onEditingComplete: submitUserName,
),
),
const SizedBox(
height: 16,
),
const VSpace(16),
SizedBox(
width: double.infinity,
child: ElevatedButton(

View File

@ -46,6 +46,11 @@ class PersonalInfoSettingGroup extends StatelessWidget {
onTap: () {
showMobileBottomSheet(
context,
showHeader: true,
title: LocaleKeys.settings_mobile_username.tr(),
showCloseButton: true,
showDragHandle: true,
showDivider: false,
builder: (_) {
return EditUsernameBottomSheet(
context,

View File

@ -204,7 +204,7 @@ class FlowyOptionTile extends StatelessWidget {
}
final padding = EdgeInsets.symmetric(
horizontal: leading == null ? 0.0 : 8.0,
horizontal: leading == null ? 0.0 : 12.0,
vertical: 16.0,
);
@ -213,7 +213,7 @@ class FlowyOptionTile extends StatelessWidget {
padding: padding,
child: FlowyText(
text!,
fontSize: 15,
fontSize: 16,
color: textColor,
),
),

View File

@ -10,7 +10,7 @@ class DragHandler extends StatelessWidget {
return Container(
height: 4,
width: 40,
margin: const EdgeInsets.symmetric(vertical: 8),
margin: const EdgeInsets.symmetric(vertical: 6),
decoration: BoxDecoration(
color: Colors.grey.shade400,
borderRadius: BorderRadius.circular(2),

View File

@ -1,4 +1,5 @@
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/database/view/database_view_list.dart';
import 'package:appflowy/mobile/presentation/database/view/edit_database_view_screen.dart';
@ -8,6 +9,7 @@ import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bl
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
@ -88,7 +90,12 @@ class MobileDatabaseControls extends StatelessWidget {
onTap: () {
showMobileBottomSheet(
context,
padding: EdgeInsets.zero,
showHeader: true,
showCloseButton: true,
showDragHandle: true,
showDivider: false,
title: LocaleKeys.grid_settings_viewList.tr(),
padding: const EdgeInsets.only(bottom: 36.0),
builder: (_) {
return MultiBlocProvider(
providers: [

View File

@ -443,33 +443,36 @@ class DocumentCoverState extends State<DocumentCover> {
title:
LocaleKeys.document_plugins_cover_changeCover.tr(),
builder: (context) {
return ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 340,
minHeight: 80,
),
child: UploadImageMenu(
supportTypes: const [
UploadImageType.color,
UploadImageType.local,
UploadImageType.url,
UploadImageType.unsplash,
],
onSelectedLocalImage: (path) async {
context.pop();
widget.onCoverChanged(CoverType.file, path);
},
onSelectedAIImage: (_) {
throw UnimplementedError();
},
onSelectedNetworkImage: (url) async {
context.pop();
widget.onCoverChanged(CoverType.file, url);
},
onSelectedColor: (color) {
context.pop();
widget.onCoverChanged(CoverType.color, color);
},
return Padding(
padding: const EdgeInsets.only(top: 8.0),
child: ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 340,
minHeight: 80,
),
child: UploadImageMenu(
supportTypes: const [
UploadImageType.color,
UploadImageType.local,
UploadImageType.url,
UploadImageType.unsplash,
],
onSelectedLocalImage: (path) async {
context.pop();
widget.onCoverChanged(CoverType.file, path);
},
onSelectedAIImage: (_) {
throw UnimplementedError();
},
onSelectedNetworkImage: (url) async {
context.pop();
widget.onCoverChanged(CoverType.file, url);
},
onSelectedColor: (color) {
context.pop();
widget.onCoverChanged(CoverType.color, color);
},
),
),
);
},

View File

@ -18,9 +18,10 @@ Future<void> showTextColorAndBackgroundColorPicker(
await showMobileBottomSheet(
context,
showHeader: true,
showCloseButton: true,
showDivider: false,
showCloseButton: false,
showDivider: true,
showDragHandle: true,
showDoneButton: true,
barrierColor: Colors.transparent,
backgroundColor: theme.toolbarMenuBackgroundColor,
elevation: 20,

View File

@ -1,5 +1,3 @@
import 'package:flutter/material.dart';
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';
@ -12,6 +10,7 @@ import 'package:appflowy/startup/tasks/app_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
final addBlockToolbarItem = AppFlowyMobileToolbarItem(
@ -58,17 +57,16 @@ Future<bool?> showAddBlockMenu(
return showMobileBottomSheet<bool>(
context,
showHeader: true,
showCloseButton: true,
showDivider: false,
showDragHandle: true,
showDoneButton: true,
barrierColor: Colors.transparent,
backgroundColor: theme.toolbarMenuBackgroundColor,
elevation: 20,
title: LocaleKeys.button_add.tr(),
padding: const EdgeInsets.fromLTRB(16, 4, 16, 0),
padding: const EdgeInsets.fromLTRB(16, 16, 16, 0),
builder: (context) {
return Padding(
padding: const EdgeInsets.only(top: 12.0, bottom: 16),
padding: const EdgeInsets.only(bottom: 16),
child: _AddBlockMenu(
selection: selection,
editorState: editorState,

View File

@ -167,25 +167,22 @@ class CloudTypeSwitcher extends StatelessWidget {
showDivider: false,
showCloseButton: false,
title: LocaleKeys.settings_menu_cloudServerType.tr(),
padding: const EdgeInsets.fromLTRB(0, 8, 0, 48),
padding: const EdgeInsets.only(bottom: 36),
builder: (context) {
return Padding(
padding: const EdgeInsets.only(top: 10),
child: Column(
children: values
.mapIndexed(
(i, e) => FlowyOptionTile.checkbox(
text: titleFromCloudType(values[i]),
isSelected: cloudType == values[i],
onTap: () {
onSelected(e);
context.pop();
},
showBottomBorder: i == values.length - 1,
),
)
.toList(),
),
return Column(
children: values
.mapIndexed(
(i, e) => FlowyOptionTile.checkbox(
text: titleFromCloudType(values[i]),
isSelected: cloudType == values[i],
onTap: () {
onSelected(e);
context.pop();
},
showBottomBorder: i == values.length - 1,
),
)
.toList(),
);
},
);

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M3.10001 5.19994H4.63334M4.63334 5.19994H16.9M4.63334 5.19994L4.63338 16.4C4.63338 16.8243 4.79492 17.2313 5.08248 17.5314C5.37004 17.8314 5.76005 18 6.16671 18H13.8334C14.24 18 14.6301 17.8314 14.9176 17.5314C15.2052 17.2313 15.3667 16.8243 15.3667 16.4V5.2L4.63334 5.19994ZM6.93338 5.2V3.6C6.93338 3.17565 7.09492 2.76869 7.38248 2.46863C7.67004 2.16857 8.06005 2 8.46671 2H11.5334C11.94 2 12.3301 2.16857 12.6176 2.46863C12.9052 2.76869 13.0667 3.17565 13.0667 3.6V5.2M8.46664 9.19994V13.9999M11.5334 9.19994V13.9999" stroke="#FB006D" stroke-width="1.375" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 720 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M9.10264 8.36644C8.6962 8.36644 8.36672 8.69592 8.36672 9.10236V15.5641C8.36672 15.9705 8.6962 16.3 9.10264 16.3H15.5644C15.9708 16.3 16.3003 15.9705 16.3003 15.5641V9.10236C16.3003 8.69592 15.9708 8.36644 15.5644 8.36644H9.10264ZM6.96668 9.10236C6.96668 7.9227 7.92298 6.9664 9.10264 6.9664H15.5644C16.744 6.9664 17.7003 7.9227 17.7003 9.10236V15.5641C17.7003 16.7437 16.744 17.7 15.5644 17.7H9.10264C7.92298 17.7 6.96668 16.7437 6.96668 15.5641V9.10236ZM4.43595 3.70009C4.24077 3.70009 4.05359 3.77762 3.91557 3.91564C3.77756 4.05365 3.70003 4.24083 3.70003 4.43601V10.8977C3.70003 11.0929 3.77756 11.2801 3.91557 11.4181C4.05359 11.5561 4.24077 11.6337 4.43595 11.6337H5.15392C5.54053 11.6337 5.85394 11.9471 5.85394 12.3337C5.85394 12.7203 5.54053 13.0337 5.15392 13.0337H4.43595C3.86946 13.0337 3.32617 12.8087 2.9256 12.4081C2.52503 12.0075 2.29999 11.4642 2.29999 10.8977V4.43601C2.29999 3.86952 2.52503 3.32623 2.9256 2.92566C3.32617 2.52509 3.86946 2.30005 4.43595 2.30005H10.8977C11.4642 2.30005 12.0075 2.52509 12.408 2.92566C12.8086 3.32623 13.0336 3.86952 13.0336 4.43601V5.15398C13.0336 5.54059 12.7202 5.854 12.3336 5.854C11.947 5.854 11.6336 5.54059 11.6336 5.15398V4.43601C11.6336 4.24083 11.5561 4.05365 11.4181 3.91564C11.28 3.77762 11.0929 3.70009 10.8977 3.70009H4.43595Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 1.4 KiB

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M10 2.19995L12.4102 7.33434L17.8 8.16273L13.9 12.157L14.8204 17.8L10 15.1343L5.17961 17.8L6.10001 12.157L2.20001 8.16273L7.58981 7.33434L10 2.19995Z" stroke="#333333" stroke-width="1.44444" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 351 B

View File

@ -0,0 +1,4 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M14.7339 2C14.0997 2 13.4915 2.25192 13.0431 2.70034L3.00447 12.739C2.91636 12.8271 2.85386 12.9375 2.82363 13.0584L2.02054 16.2708C1.96197 16.505 2.03062 16.7529 2.20138 16.9236C2.37214 17.0944 2.61998 17.163 2.85426 17.1045L6.06663 16.3014C6.18751 16.2712 6.29791 16.2087 6.38602 16.1205L16.4247 6.08189C16.6467 5.85985 16.8228 5.59626 16.943 5.30616C17.0632 5.01605 17.125 4.70512 17.125 4.39112C17.125 4.07711 17.0632 3.76618 16.943 3.47608C16.8228 3.18597 16.6467 2.92238 16.4247 2.70034C16.2026 2.47831 15.939 2.30218 15.6489 2.18201C15.3588 2.06185 15.0479 2 14.7339 2ZM14.0154 3.67261C14.206 3.48205 14.4644 3.375 14.7339 3.375C14.8673 3.375 14.9995 3.40128 15.1227 3.45235C15.246 3.50341 15.358 3.57826 15.4524 3.67261C15.5468 3.76697 15.6216 3.87898 15.6727 4.00226C15.7237 4.12555 15.75 4.25768 15.75 4.39112C15.75 4.52455 15.7237 4.65669 15.6727 4.77997C15.6216 4.90325 15.5468 5.01526 15.4524 5.10962L5.5484 15.0136L3.63239 15.4926L4.11139 13.5766L14.0154 3.67261Z" fill="#333333"/>
<path d="M9.56251 15.75C9.18282 15.75 8.87501 16.0578 8.87501 16.4375C8.87501 16.8172 9.18282 17.125 9.56251 17.125H17.8125C18.1922 17.125 18.5 16.8172 18.5 16.4375C18.5 16.0578 18.1922 15.75 17.8125 15.75H9.56251Z" fill="#333333"/>
</svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@ -0,0 +1,5 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M17.85 15.7893V17.4393H3V15.7893" stroke="#333333" stroke-width="1.386" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M12.8997 2L17.0247 6.125L12.8997 10.25" stroke="#333333" stroke-width="1.65" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M17.025 6.12683C8.775 6.12683 3 7.36433 3 12.7268" stroke="#333333" stroke-width="1.386" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 515 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M16.9986 9.85711C16.197 10.4238 15.2185 10.7568 14.1622 10.7568C11.4455 10.7568 9.24324 8.55448 9.24324 5.83784C9.24324 4.78153 9.5762 3.80298 10.1429 3.00143C10.0954 3.00048 10.0477 3 10 3C6.13401 3 3 6.13401 3 10C3 13.866 6.13401 17 10 17C13.866 17 17 13.866 17 10C17 9.95226 16.9995 9.90463 16.9986 9.85711Z" stroke="#333333" stroke-width="1.3" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 509 B

View File

@ -0,0 +1,10 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<g clip-path="url(#clip0_1050_12687)">
<path d="M10.0002 2.3396V0.999802M4.58355 15.4168L3.63616 16.3642M10.0002 19.0002V17.6604M16.364 3.63595L15.4166 4.58333M17.6602 10H19M15.4166 15.4167L16.364 16.3641M1 10H2.3398M3.63609 3.6359L4.58348 4.58328M13.2653 6.73477C15.0686 8.5381 15.0686 11.4619 13.2653 13.2652C11.462 15.0685 8.53819 15.0685 6.73486 13.2652C4.93153 11.4619 4.93153 8.5381 6.73486 6.73477C8.53819 4.93144 11.462 4.93144 13.2653 6.73477Z" stroke="#333333" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
</g>
<defs>
<clipPath id="clip0_1050_12687">
<rect width="20" height="20" fill="white"/>
</clipPath>
</defs>
</svg>

After

Width:  |  Height:  |  Size: 751 B

View File

@ -0,0 +1,3 @@
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M7.91201 16.3659H12.088M6.05601 19H13.944C14.9691 19 15.8 18.2138 15.8 17.2439V2.7561C15.8 1.78623 14.9691 1 13.944 1H6.05601C5.03097 1 4.20001 1.78623 4.20001 2.7561V17.2439C4.20001 18.2138 5.03097 19 6.05601 19Z" stroke="#333333" stroke-width="1.24222" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

After

Width:  |  Height:  |  Size: 416 B