feat:add toast in trash and confirm dialog + fix issues from launch review (#3787)

* chore: improve trash button

* feat: improve restore all&delete all

* refactor: add showFlowyMobileConfirmDialog

* feat: add toast in delete/restore single file

* refactor: refactor to TrashActionType enum

* fix: text invisible in signin page in dark mode

* feat: add FlowyMobileErrorStateContainer to display error state

* refactor: add FlowyMobileStateContainer to handle empty or error state

- Replace MobileErrorPage by FlowyMobileStateContainer.error
- Implement app version in reporting issue on github
- Implement FlowyMobileStateContainer in trash,setting,favorite and mobile view page

* refactor: unify bottom sheet style

- Unify bottom sheet style in add new page, page action, and trash action
- Add icon color in BottomSheetActionWidget for future use
- Add theme color in MobileBottomSheetDragHandle

* chore: unify Appbar style

* chore: remove the more button when trash list is empty

* fix: show bottom sheet error

* fix: fix merge and ui issue

* refactor: refactor ViewPageBottomSheet and origanize code

* chore: add icon color for favorite button

* fix: add missing icon color and delete comments

---------

Co-authored-by: Lucas.Xu <lucas.xu@appflowy.io>
This commit is contained in:
Yijing Huang 2023-11-02 11:15:15 -07:00 committed by GitHub
parent a93d325e6a
commit 73ea1a0685
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
25 changed files with 594 additions and 574 deletions

View File

@ -64,7 +64,6 @@ ThemeData getMobileThemeData(
appBarTheme: AppBarTheme(
foregroundColor: mobileColorTheme.onBackground,
backgroundColor: mobileColorTheme.background,
elevation: 80,
centerTitle: false,
titleTextStyle: TextStyle(
color: mobileColorTheme.onBackground,
@ -116,7 +115,7 @@ ThemeData getMobileThemeData(
foregroundColor: MaterialStateProperty.all(
mobileColorTheme.onBackground,
),
backgroundColor: MaterialStateProperty.all(Colors.white),
backgroundColor: MaterialStateProperty.all(mobileColorTheme.background),
shape: MaterialStateProperty.all(
RoundedRectangleBorder(
borderRadius: BorderRadius.circular(6),
@ -129,7 +128,7 @@ ThemeData getMobileThemeData(
),
),
padding: MaterialStateProperty.all(
const EdgeInsets.symmetric(horizontal: 16),
const EdgeInsets.symmetric(horizontal: 8, vertical: 12),
),
// splash color
overlayColor: MaterialStateProperty.all(

View File

@ -1,8 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
import 'package:appflowy/mobile/presentation/base/app_bar_actions.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_page.dart';
import 'package:appflowy/mobile/presentation/error/error_page.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
@ -56,8 +55,11 @@ class _MobileViewPageState extends State<MobileViewPage> {
child: CircularProgressIndicator(),
);
} else if (!state.hasData) {
body = MobileErrorPage(
message: LocaleKeys.error_loadingViewError.tr(),
body = FlowyMobileStateContainer.error(
emoji: '😔',
title: LocaleKeys.error_weAreSorry.tr(),
description: LocaleKeys.error_loadingViewError.tr(),
errorMsg: state.error.toString(),
);
} else {
body = state.data!.fold((view) {
@ -65,8 +67,11 @@ class _MobileViewPageState extends State<MobileViewPage> {
actions.add(_buildAppBarMoreButton(view));
return view.plugin().widgetBuilder.buildWidget(shrinkWrap: false);
}, (error) {
return MobileErrorPage(
message: error.toString(),
return FlowyMobileStateContainer.error(
emoji: '😔',
title: LocaleKeys.error_weAreSorry.tr(),
description: LocaleKeys.error_loadingViewError.tr(),
errorMsg: error.toString(),
);
});
}

View File

@ -1,146 +1,9 @@
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_drag_handler.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_rename_widget.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_body.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_header.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-folder2/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';
Future<void> showMobileBottomSheet({
required BuildContext context,
required WidgetBuilder builder,
}) async {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
useSafeArea: true,
shape: const RoundedRectangleBorder(
borderRadius: BorderRadius.only(
topLeft: Radius.circular(8.0),
topRight: Radius.circular(8.0),
),
),
builder: builder,
);
}
enum MobileBottomSheetType {
view,
rename,
}
class MobileViewItemBottomSheet extends StatefulWidget {
const MobileViewItemBottomSheet({
super.key,
required this.view,
this.defaultType = MobileBottomSheetType.view,
});
final ViewPB view;
final MobileBottomSheetType defaultType;
@override
State<MobileViewItemBottomSheet> createState() =>
_MobileViewItemBottomSheetState();
}
class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
MobileBottomSheetType type = MobileBottomSheetType.view;
@override
initState() {
super.initState();
type = widget.defaultType;
}
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// drag handler
const MobileBottomSheetDragHandler(),
// header
_buildHeader(),
const VSpace(8.0),
const Divider(),
// body
_buildBody(),
const VSpace(12.0),
],
);
}
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(
isFavorite: widget.view.isFavorite,
onAction: (action) {
switch (action) {
case MobileViewItemBottomSheetBodyAction.rename:
setState(() {
type = MobileBottomSheetType.rename;
});
break;
case MobileViewItemBottomSheetBodyAction.duplicate:
context.pop();
context.read<ViewBloc>().add(const ViewEvent.duplicate());
break;
case MobileViewItemBottomSheetBodyAction.share:
// unimplemented
context.pop();
break;
case MobileViewItemBottomSheetBodyAction.delete:
context.pop();
context.read<ViewBloc>().add(const ViewEvent.delete());
break;
case MobileViewItemBottomSheetBodyAction.addToFavorites:
case MobileViewItemBottomSheetBodyAction.removeFromFavorites:
context.pop();
context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(widget.view));
break;
}
},
);
case MobileBottomSheetType.rename:
return MobileBottomSheetRenameWidget(
name: widget.view.name,
onRename: (name) {
if (name != widget.view.name) {
context.read<ViewBloc>().add(ViewEvent.rename(name));
}
context.pop();
},
);
}
}
}
export 'bottom_sheet_action_widget.dart';
export 'bottom_sheet_add_new_page.dart';
export 'bottom_sheet_drag_handler.dart';
export 'bottom_sheet_rename_widget.dart';
export 'bottom_sheet_view_item_body.dart';
export 'bottom_sheet_view_item_header.dart';
export 'bottom_sheet_view_page.dart';
export 'default_mobile_action_pane.dart';
export 'show_mobile_bottom_sheet.dart';

View File

@ -1,8 +1,5 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/mobile/presentation/base/box_container.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class BottomSheetActionWidget extends StatelessWidget {
const BottomSheetActionWidget({
@ -10,42 +7,31 @@ class BottomSheetActionWidget extends StatelessWidget {
required this.svg,
required this.text,
required this.onTap,
this.iconColor,
});
final FlowySvgData svg;
final String text;
final VoidCallback onTap;
final Color? iconColor;
@override
Widget build(BuildContext context) {
return FlowyBoxContainer(
child: InkWell(
onTap: () {
HapticFeedback.mediumImpact();
onTap();
},
enableFeedback: true,
child: Padding(
padding: const EdgeInsets.symmetric(
vertical: 10.0,
horizontal: 12.0,
),
child: Row(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.center,
children: [
FlowySvg(
svg,
size: const Size.square(24.0),
blendMode: BlendMode.dst,
),
const HSpace(6.0),
FlowyText(text),
const Spacer(),
],
),
),
final iconColor =
this.iconColor ?? Theme.of(context).colorScheme.onBackground;
return OutlinedButton.icon(
icon: FlowySvg(
svg,
size: const Size.square(22.0),
color: iconColor,
),
label: Text(text),
style: Theme.of(context)
.outlinedButtonTheme
.style
?.copyWith(alignment: Alignment.centerLeft),
onPressed: onTap,
);
}
}

View File

@ -1,8 +1,6 @@
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/bottom_sheet/bottom_sheet_drag_handler.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_header.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -21,46 +19,9 @@ class AddNewPageWidgetBottomSheet extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// drag handler
const MobileBottomSheetDragHandler(),
// header
MobileViewItemBottomSheetHeader(
showBackButton: false,
view: view,
onBack: () {},
),
const VSpace(8.0),
const Divider(),
// body
_AddNewPageBody(
onAction: onAction,
),
const VSpace(24.0),
],
);
}
}
class _AddNewPageBody extends StatelessWidget {
const _AddNewPageBody({
required this.onAction,
});
final void Function(ViewLayoutPB layout) onAction;
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
children: [
// rename, duplicate
// new document, new grid
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -69,6 +30,7 @@ class _AddNewPageBody extends StatelessWidget {
onTap: () => onAction(ViewLayoutPB.Document),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.grid_s,
@ -78,10 +40,10 @@ class _AddNewPageBody extends StatelessWidget {
),
],
),
const VSpace(8),
// share, delete
// new board, new calendar
Row(
mainAxisSize: MainAxisSize.min,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -90,6 +52,7 @@ class _AddNewPageBody extends StatelessWidget {
onTap: () => onAction(ViewLayoutPB.Board),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.date_s,

View File

@ -12,7 +12,7 @@ class MobileBottomSheetDragHandler extends StatelessWidget {
height: 4,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(2.0),
color: Theme.of(context).colorScheme.onSecondary,
color: Theme.of(context).hintColor,
),
),
);

View File

@ -2,6 +2,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:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
enum MobileViewItemBottomSheetBodyAction {
@ -26,12 +27,11 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// rename, duplicate
Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -42,6 +42,7 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_duplicate_m,
@ -53,10 +54,11 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
),
],
),
const VSpace(8),
// share, delete
Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -67,6 +69,7 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_delete_m,
@ -78,13 +81,15 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
),
],
),
const VSpace(8),
// remove from favorites
// 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,
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),

View File

@ -1,6 +1,6 @@
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
import 'package:go_router/go_router.dart';
class MobileViewItemBottomSheetHeader extends StatelessWidget {
const MobileViewItemBottomSheetHeader({
@ -16,8 +16,8 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [
// back button,
showBackButton
@ -31,14 +31,23 @@ class MobileViewItemBottomSheetHeader extends StatelessWidget {
),
),
)
: const HSpace(40.0),
: const SizedBox.shrink(),
// title
FlowyText.regular(
view.name,
fontSize: 16.0,
Expanded(
child: Text(
view.name,
style: theme.textTheme.labelSmall,
),
),
// placeholder, ensure the title is centered
const HSpace(40.0),
IconButton(
icon: Icon(
Icons.close,
color: theme.hintColor,
),
onPressed: () {
context.pop();
},
)
],
);
}

View File

@ -1,10 +1,6 @@
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/bottom_sheet/bottom_sheet_drag_handler.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_rename_widget.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_header.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/view.pb.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
@ -47,21 +43,18 @@ class _ViewPageBottomSheetState extends State<ViewPageBottomSheet> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// drag handler
const MobileBottomSheetDragHandler(),
// header
_buildHeader(),
const VSpace(8.0),
const Divider(),
// body
_buildBody(),
const VSpace(24.0),
],
return Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// header
_buildHeader(),
const VSpace(16),
// body
_buildBody(),
],
),
);
}
@ -125,12 +118,11 @@ class MobileViewBottomSheetBody extends StatelessWidget {
Widget build(BuildContext context) {
final isFavorite = view.isFavorite;
return Column(
mainAxisSize: MainAxisSize.min,
mainAxisAlignment: MainAxisAlignment.spaceEvenly,
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
// undo, redo
Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -141,6 +133,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_redo_m,
@ -152,10 +145,11 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
],
),
const VSpace(8),
// rename, duplicate
Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -166,6 +160,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_duplicate_m,
@ -177,10 +172,11 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
],
),
const VSpace(8),
// share, delete
Row(
mainAxisSize: MainAxisSize.min,
mainAxisSize: MainAxisSize.max,
children: [
Expanded(
child: BottomSheetActionWidget(
@ -191,6 +187,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
),
),
const HSpace(8),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_delete_m,
@ -202,12 +199,15 @@ class MobileViewBottomSheetBody extends StatelessWidget {
),
],
),
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,
text: isFavorite
? LocaleKeys.button_removeFromFavorites.tr()
: LocaleKeys.button_addToFavorites.tr(),
@ -217,6 +217,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
: MobileViewBottomSheetBodyAction.addToFavorites,
),
),
const VSpace(8),
// help center
BottomSheetActionWidget(

View File

@ -1,5 +1,5 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/page_item/mobile_slide_action_button.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';

View File

@ -1,7 +1,4 @@
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_drag_handler.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_rename_widget.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_body.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_view_item_header.dart';
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-folder2/protobuf.dart';
@ -10,6 +7,19 @@ import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart';
Future<void> showMobileBottomSheet({
required BuildContext context,
required WidgetBuilder builder,
}) async {
showModalBottomSheet(
context: context,
isScrollControlled: true,
enableDrag: true,
useSafeArea: true,
builder: builder,
);
}
enum MobileBottomSheetType {
view,
rename,
@ -42,21 +52,18 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
@override
Widget build(BuildContext context) {
return Column(
mainAxisSize: MainAxisSize.min,
children: [
// drag handler
const MobileBottomSheetDragHandler(),
// header
_buildHeader(),
const VSpace(8.0),
const Divider(),
// body
_buildBody(),
const VSpace(24.0),
],
return Padding(
padding: const EdgeInsets.fromLTRB(16, 16, 16, 32),
child: Column(
mainAxisSize: MainAxisSize.min,
children: [
// header
_buildHeader(),
const VSpace(16),
// body
_buildBody(),
],
),
);
}
@ -90,23 +97,24 @@ class _MobileViewItemBottomSheetState extends State<MobileViewItemBottomSheet> {
});
break;
case MobileViewItemBottomSheetBodyAction.duplicate:
context.read<ViewBloc>().add(const ViewEvent.duplicate());
context.pop();
context.read<ViewBloc>().add(const ViewEvent.duplicate());
break;
case MobileViewItemBottomSheetBodyAction.share:
// unimplemented
context.pop();
break;
case MobileViewItemBottomSheetBodyAction.delete:
context.read<ViewBloc>().add(const ViewEvent.delete());
context.pop();
context.read<ViewBloc>().add(const ViewEvent.delete());
break;
case MobileViewItemBottomSheetBodyAction.addToFavorites:
case MobileViewItemBottomSheetBodyAction.removeFromFavorites:
context.pop();
context
.read<FavoriteBloc>()
.add(FavoriteEvent.toggle(widget.view));
context.pop();
break;
}
},

View File

@ -1,49 +0,0 @@
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';
class MobileErrorPage extends StatelessWidget {
const MobileErrorPage({
super.key,
this.header,
this.title,
required this.message,
});
final Widget? header;
final String? title;
final String message;
@override
Widget build(BuildContext context) {
return Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
header != null
? header!
: const FlowyText.semibold(
'😔',
fontSize: 50,
),
const VSpace(14.0),
FlowyText.semibold(
title ?? LocaleKeys.error_weAreSorry.tr(),
fontSize: 32,
textAlign: TextAlign.center,
),
const VSpace(4.0),
Padding(
padding: const EdgeInsets.symmetric(horizontal: 24.0),
child: FlowyText.regular(
message,
fontSize: 16,
maxLines: 100,
color: Colors.grey, // FIXME: use theme color
textAlign: TextAlign.center,
),
),
],
);
}
}

View File

@ -1,7 +1,7 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/error/error_page.dart';
import 'package:appflowy/mobile/presentation/home/favorite_folder/mobile_home_favorite_folder.dart';
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_state_container.dart';
import 'package:appflowy/workspace/application/favorite/favorite_bloc.dart';
import 'package:appflowy/workspace/application/menu/menu_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart';
@ -49,27 +49,27 @@ class MobileFavoritePageFolder extends StatelessWidget {
builder: (context) {
final favoriteState = context.watch<FavoriteBloc>().state;
if (favoriteState.views.isEmpty) {
return MobileErrorPage(
header: const FlowyText.semibold(
'😁',
fontSize: 50,
),
return FlowyMobileStateContainer.info(
emoji: '😁',
title: LocaleKeys.favorite_noFavorite.tr(),
message: LocaleKeys.favorite_noFavoriteHintText.tr(),
description: LocaleKeys.favorite_noFavoriteHintText.tr(),
);
}
return Scrollbar(
child: SingleChildScrollView(
child: SlidableAutoCloseBehavior(
child: Column(
children: [
MobileFavoriteFolder(
showHeader: false,
forceExpanded: true,
views: favoriteState.views,
),
const VSpace(100.0),
],
child: Padding(
padding: const EdgeInsets.all(8.0),
child: SlidableAutoCloseBehavior(
child: Column(
children: [
MobileFavoriteFolder(
showHeader: false,
forceExpanded: true,
views: favoriteState.views,
),
const VSpace(100.0),
],
),
),
),
),

View File

@ -82,12 +82,9 @@ class MobileFavoritePage extends StatelessWidget {
// Folder
Expanded(
child: Padding(
padding: const EdgeInsets.all(8.0),
child: MobileFavoritePageFolder(
userProfile: userProfile,
workspaceSetting: workspaceSetting,
),
child: MobileFavoritePageFolder(
userProfile: userProfile,
workspaceSetting: workspaceSetting,
),
),
],

View File

@ -110,7 +110,10 @@ class MobileHomePage extends StatelessWidget {
),
),
const SizedBox(height: 8),
const _TrashButton(),
const Padding(
padding: EdgeInsets.symmetric(horizontal: 16),
child: _TrashButton(),
),
],
),
),
@ -142,7 +145,10 @@ class _TrashButton extends StatelessWidget {
LocaleKeys.trash_text.tr(),
style: Theme.of(context).textTheme.labelMedium,
),
style: const ButtonStyle(alignment: Alignment.centerLeft),
style: const ButtonStyle(
alignment: Alignment.centerLeft,
splashFactory: NoSplash.splashFactory,
),
),
);
}

View File

@ -28,6 +28,7 @@ class MobileHomePageRecentFilesWidget extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
// TODO: implement the details later.
return SizedBox(
height: 168,
@ -54,13 +55,10 @@ class MobileHomePageRecentFilesWidget extends StatelessWidget {
return Container(
width: 120,
decoration: BoxDecoration(
color: Theme.of(context).colorScheme.background,
color: theme.colorScheme.background,
borderRadius: BorderRadius.circular(8),
border: Border.all(
color: Theme.of(context)
.colorScheme
.outline
.withOpacity(0.5),
color: theme.colorScheme.outline.withOpacity(0.5),
),
),
child: Stack(
@ -104,14 +102,9 @@ class MobileHomePageRecentFilesWidget extends StatelessWidget {
child: Text(
recentFilesList[index].title,
softWrap: true,
style: Theme.of(context)
.textTheme
.bodyMedium
?.copyWith(
color: Theme.of(context)
.colorScheme
.onBackground,
),
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onBackground,
),
maxLines: 2,
),
),

View File

@ -1,6 +1,6 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/presentation.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/auth/auth_service.dart';
import 'package:easy_localization/easy_localization.dart';
@ -23,33 +23,47 @@ class _MobileHomeSettingPageState extends State<MobileHomeSettingPage> {
return FutureBuilder(
future: getIt<AuthService>().getUser(),
builder: ((context, snapshot) {
String? errorMsg;
if (!snapshot.hasData) {
return const Center(child: CircularProgressIndicator.adaptive());
}
final userProfile = snapshot.data?.fold((error) => null, (userProfile) {
final userProfile = snapshot.data?.fold((error) {
errorMsg = error.msg;
return null;
}, (userProfile) {
return userProfile;
});
return Scaffold(
appBar: AppBar(
title: Text(LocaleKeys.settings_title.tr()),
),
body: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
PersonalInfoSettingGroup(
userProfile: userProfile,
body: userProfile == null
? FlowyMobileStateContainer.error(
emoji: '🛸',
title: LocaleKeys.settings_mobile_userprofileError.tr(),
description: LocaleKeys
.settings_mobile_userprofileErrorDescription
.tr(),
errorMsg: errorMsg,
)
: SingleChildScrollView(
child: Padding(
padding: const EdgeInsets.all(16),
child: Column(
children: [
PersonalInfoSettingGroup(
userProfile: userProfile,
),
// TODO(yijing): implement this along with Notification Page
const NotificationsSettingGroup(),
const AppearanceSettingGroup(),
const SupportSettingGroup(),
const AboutSettingGroup(),
],
),
),
// TODO(yijing): implement this along with Notification Page
const NotificationsSettingGroup(),
const AppearanceSettingGroup(),
const SupportSettingGroup(),
const AboutSettingGroup(),
],
),
),
),
),
);
}),
);

View File

@ -1,12 +1,13 @@
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/show_flowy_mobile_bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/trash/application/prelude.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:go_router/go_router.dart';
class MobileHomeTrashPage extends StatelessWidget {
@ -18,61 +19,53 @@ class MobileHomeTrashPage extends StatelessWidget {
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => getIt<TrashBloc>()..add(const TrashEvent.initial()),
child: Builder(
builder: (context) {
child: BlocBuilder<TrashBloc, TrashState>(
builder: (context, state) {
return Scaffold(
appBar: AppBar(
title: Text(LocaleKeys.trash_text.tr()),
elevation: 0,
actions: [
IconButton(
splashRadius: 20,
icon: const Icon(Icons.more_horiz),
onPressed: () {
showFlowyMobileBottomSheet(
context,
title: LocaleKeys.trash_mobile_actions.tr(),
builder: (_) => Row(
children: [
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_restore_m,
text: LocaleKeys.trash_restoreAll.tr(),
onTap: () {
context
..read<TrashBloc>()
.add(const TrashEvent.restoreAll())
..pop();
},
state.objects.isEmpty
? const SizedBox.shrink()
: IconButton(
splashRadius: 20,
icon: const Icon(Icons.more_horiz),
onPressed: () {
final trashBloc = context.read<TrashBloc>();
showFlowyMobileBottomSheet(
context,
title: LocaleKeys.trash_mobile_actions.tr(),
builder: (_) => Row(
children: [
Expanded(
child: _TrashActionAllButton(
trashBloc: trashBloc,
type: _TrashActionType.deleteAll,
),
),
const SizedBox(
width: 16,
),
Expanded(
child: _TrashActionAllButton(
trashBloc: trashBloc,
type: _TrashActionType.restoreAll,
),
)
],
),
),
Expanded(
child: BottomSheetActionWidget(
svg: FlowySvgs.m_delete_m,
text: LocaleKeys.trash_deleteAll.tr(),
onTap: () {
context
..read<TrashBloc>()
.add(const TrashEvent.deleteAll())
..pop();
},
),
)
],
);
},
),
);
},
),
],
),
body: BlocBuilder<TrashBloc, TrashState>(
builder: (_, state) {
if (state.objects.isEmpty) {
return const _TrashEmptyPage();
}
return _DeletedFilesListView(state);
},
),
body: state.objects.isEmpty
? FlowyMobileStateContainer.info(
emoji: '🗑️',
title: LocaleKeys.trash_mobile_empty.tr(),
description: LocaleKeys.trash_mobile_emptyDescription.tr(),
)
: _DeletedFilesListView(state),
);
},
),
@ -80,6 +73,76 @@ class MobileHomeTrashPage extends StatelessWidget {
}
}
enum _TrashActionType {
restoreAll,
deleteAll,
}
class _TrashActionAllButton extends StatelessWidget {
/// Switch between 'delete all' and 'restore all' feature
const _TrashActionAllButton({
this.type = _TrashActionType.deleteAll,
required this.trashBloc,
});
final _TrashActionType type;
final TrashBloc trashBloc;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
final isDeleteAll = type == _TrashActionType.deleteAll;
return BlocProvider.value(
value: trashBloc,
child: BottomSheetActionWidget(
svg: isDeleteAll ? FlowySvgs.m_delete_m : FlowySvgs.m_restore_m,
text: isDeleteAll
? LocaleKeys.trash_deleteAll.tr()
: LocaleKeys.trash_restoreAll.tr(),
onTap: () {
final trashList = trashBloc.state.objects;
if (trashList.isNotEmpty) {
context.pop();
showFlowyMobileConfirmDialog(
context,
title: isDeleteAll
? LocaleKeys.trash_confirmDeleteAll_title.tr()
: LocaleKeys.trash_restoreAll.tr(),
content: isDeleteAll
? LocaleKeys.trash_confirmDeleteAll_caption.tr()
: LocaleKeys.trash_confirmRestoreAll_caption.tr(),
actionButtonTitle: isDeleteAll
? LocaleKeys.trash_deleteAll.tr()
: LocaleKeys.trash_restoreAll.tr(),
actionButtonColor: isDeleteAll
? theme.colorScheme.error
: theme.colorScheme.primary,
onActionButtonPressed: () {
if (isDeleteAll) {
trashBloc.add(
const TrashEvent.deleteAll(),
);
} else {
trashBloc.add(
const TrashEvent.restoreAll(),
);
}
},
cancelButtonTitle: LocaleKeys.button_cancel.tr(),
);
} else {
// when there is no deleted files
// show toast
Fluttertoast.showToast(
msg: LocaleKeys.trash_mobile_empty.tr(),
gravity: ToastGravity.CENTER,
);
}
},
),
);
}
}
class _DeletedFilesListView extends StatelessWidget {
const _DeletedFilesListView(
this.state,
@ -89,95 +152,75 @@ class _DeletedFilesListView extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return ListView.builder(
itemBuilder: (context, index) {
final object = state.objects[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ListTile(
// TODO(Yijing): implement file type after TrashPB has file type
leading: FlowySvg(
FlowySvgs.documents_s,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
),
title: Text(
object.name,
style: theme.textTheme.labelMedium
?.copyWith(color: theme.colorScheme.onBackground),
),
horizontalTitleGap: 0,
// TODO(yiing): needs improve by container/surface theme color
tileColor: theme.colorScheme.onSurface.withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
// TODO(yijing): extract icon button
IconButton(
splashRadius: 20,
icon: FlowySvg(
FlowySvgs.m_restore_m,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
return Padding(
padding: const EdgeInsets.symmetric(vertical: 8),
child: ListView.builder(
itemBuilder: (context, index) {
final object = state.objects[index];
return Padding(
padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 4),
child: ListTile(
// TODO(Yijing): implement file type after TrashPB has file type
leading: FlowySvg(
FlowySvgs.documents_s,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
),
title: Text(
object.name,
style: theme.textTheme.labelMedium
?.copyWith(color: theme.colorScheme.onBackground),
),
horizontalTitleGap: 0,
// TODO(yiing): needs improve by container/surface theme color
tileColor: theme.colorScheme.onSurface.withOpacity(0.1),
shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8),
),
trailing: Row(
mainAxisSize: MainAxisSize.min,
children: [
// TODO(yijing): extract icon button
IconButton(
splashRadius: 20,
icon: FlowySvg(
FlowySvgs.m_restore_m,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
),
onPressed: () {
context
.read<TrashBloc>()
.add(TrashEvent.putback(object.id));
Fluttertoast.showToast(
msg:
'${object.name} ${LocaleKeys.trash_mobile_isRestored.tr()}',
gravity: ToastGravity.BOTTOM,
);
},
),
onPressed: () {
context
.read<TrashBloc>()
.add(TrashEvent.putback(object.id));
},
),
IconButton(
splashRadius: 20,
icon: FlowySvg(
FlowySvgs.m_delete_m,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
),
onPressed: () {
context.read<TrashBloc>().add(TrashEvent.delete(object));
},
)
],
IconButton(
splashRadius: 20,
icon: FlowySvg(
FlowySvgs.m_delete_m,
size: const Size.square(24),
color: theme.colorScheme.onSurface,
),
onPressed: () {
context.read<TrashBloc>().add(TrashEvent.delete(object));
Fluttertoast.showToast(
msg:
'${object.name} ${LocaleKeys.trash_mobile_isDeleted.tr()}',
gravity: ToastGravity.BOTTOM,
);
},
)
],
),
),
),
);
},
itemCount: state.objects.length,
);
}
}
class _TrashEmptyPage extends StatelessWidget {
const _TrashEmptyPage();
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
'🗑️',
style: TextStyle(fontSize: 40),
),
const SizedBox(height: 8),
Text(
LocaleKeys.trash_mobile_empty.tr(),
style: theme.textTheme.labelLarge,
),
const SizedBox(height: 4),
Text(
LocaleKeys.trash_mobile_emptyDescription.tr(),
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.hintColor,
),
),
],
);
},
itemCount: state.objects.length,
),
);
}

View File

@ -1,8 +1,8 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/application/mobile_router.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet_add_new_page.dart';
import 'package:appflowy/mobile/presentation/page_item/mobile_view_item_add_button.dart';
import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/workspace/application/sidebar/folder/folder_bloc.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart';
@ -395,20 +395,24 @@ class _SingleMobileInnerViewItemState extends State<SingleMobileInnerViewItem> {
Widget _buildViewAddButton(BuildContext context) {
return MobileViewAddButton(
onPressed: () {
showMobileBottomSheet(
context: context,
builder: (_) => AddNewPageWidgetBottomSheet(
view: widget.view,
onAction: (layout) {
context.pop();
context.read<ViewBloc>().add(
ViewEvent.createView(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout,
),
);
},
),
final title = widget.view.name;
showFlowyMobileBottomSheet(
context,
title: title,
builder: (_) {
return AddNewPageWidgetBottomSheet(
view: widget.view,
onAction: (layout) {
context.pop();
context.read<ViewBloc>().add(
ViewEvent.createView(
LocaleKeys.menuAppHeader_defaultNewPageName.tr(),
layout,
),
);
},
);
},
);
},
);

View File

@ -16,7 +16,7 @@ class PersonalInfoSettingGroup extends StatelessWidget {
required this.userProfile,
});
final UserProfilePB? userProfile;
final UserProfilePB userProfile;
@override
Widget build(BuildContext context) {
@ -33,9 +33,9 @@ class PersonalInfoSettingGroup extends StatelessWidget {
settingItemList: [
MobileSettingItem(
name: userName,
subtitle: isCloudEnabled && userProfile != null
subtitle: isCloudEnabled
? Text(
userProfile!.email,
userProfile.email,
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.colorScheme.onSurface,
),

View File

@ -4,6 +4,7 @@ import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
import 'widgets/widgets.dart';
@ -14,32 +15,33 @@ class SupportSettingGroup extends StatelessWidget {
@override
Widget build(BuildContext context) {
return MobileSettingGroup(
groupTitle: LocaleKeys.settings_mobile_support.tr(),
settingItemList: [
// 'Help Center'
MobileSettingItem(
name: LocaleKeys.settings_mobile_joinDiscord.tr(),
trailing: const Icon(
Icons.chevron_right,
return FutureBuilder(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) => MobileSettingGroup(
groupTitle: LocaleKeys.settings_mobile_support.tr(),
settingItemList: [
MobileSettingItem(
name: LocaleKeys.settings_mobile_joinDiscord.tr(),
trailing: const Icon(
Icons.chevron_right,
),
onTap: () => safeLaunchUrl('https://discord.gg/JucBXeU2FE'),
),
onTap: () => safeLaunchUrl('https://discord.gg/JucBXeU2FE'),
),
MobileSettingItem(
name: LocaleKeys.workspace_errorActions_reportIssue.tr(),
trailing: const Icon(
Icons.chevron_right,
MobileSettingItem(
name: LocaleKeys.workspace_errorActions_reportIssue.tr(),
trailing: const Icon(
Icons.chevron_right,
),
onTap: () {
final String? version = snapshot.data?.version;
final String os = Platform.operatingSystem;
safeLaunchUrl(
'https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&projects=&template=bug_report.yaml&title=[Bug]%20Mobile:%20&version=$version&os=$os',
);
},
),
onTap: () {
// TODO(yijing): get app version before release
const String version = 'Beta';
final String os = Platform.operatingSystem;
safeLaunchUrl(
'https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&projects=&template=bug_report.yaml&title=[Bug]%20Mobile:%20&version=$version&os=$os',
);
},
),
],
],
),
);
}
}

View File

@ -0,0 +1,102 @@
import 'dart:io';
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
import 'package:package_info_plus/package_info_plus.dart';
enum _FlowyMobileStateContainerType {
info,
error,
}
/// Used to display info(like empty state) or error state
/// error state has two buttons to report issue with error message or reach out on discord
class FlowyMobileStateContainer extends StatelessWidget {
const FlowyMobileStateContainer.error({
this.emoji,
required this.title,
this.description,
required this.errorMsg,
super.key,
}) : _stateType = _FlowyMobileStateContainerType.error;
const FlowyMobileStateContainer.info({
this.emoji,
required this.title,
this.description,
super.key,
}) : errorMsg = null,
_stateType = _FlowyMobileStateContainerType.info;
final String? emoji;
final String title;
final String? description;
final String? errorMsg;
final _FlowyMobileStateContainerType _stateType;
@override
Widget build(BuildContext context) {
final theme = Theme.of(context);
return SizedBox.expand(
child: Padding(
padding: const EdgeInsets.symmetric(vertical: 8, horizontal: 32),
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Text(
emoji ?? '',
style: const TextStyle(fontSize: 40),
),
const SizedBox(height: 8),
Text(
title,
style: theme.textTheme.labelLarge,
),
const SizedBox(height: 4),
Text(
description ?? '',
style: theme.textTheme.bodyMedium?.copyWith(
color: theme.hintColor,
),
),
if (_stateType == _FlowyMobileStateContainerType.error) ...[
const SizedBox(height: 8),
FutureBuilder(
future: PackageInfo.fromPlatform(),
builder: (context, snapshot) {
return Column(
crossAxisAlignment: CrossAxisAlignment.stretch,
children: [
OutlinedButton(
onPressed: () {
final String? version = snapshot.data?.version;
final String os = Platform.operatingSystem;
safeLaunchUrl(
'https://github.com/AppFlowy-IO/AppFlowy/issues/new?assignees=&labels=&projects=&template=bug_report.yaml&title=[Bug]%20Mobile:%20&version=$version&os=$os&context=Error%20log:%20$errorMsg',
);
},
child: Text(
LocaleKeys.workspace_errorActions_reportIssue.tr(),
),
),
OutlinedButton(
onPressed: () =>
safeLaunchUrl('https://discord.gg/JucBXeU2FE'),
child: Text(
LocaleKeys.workspace_errorActions_reachOut.tr(),
),
),
],
);
},
)
]
],
),
),
);
}
}

View File

@ -0,0 +1,62 @@
import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flutter/material.dart';
///show the dialog to confirm one single action
///[onActionButtonPressed] and [onCancelButtonPressed] end with close the dialog
Future<T?> showFlowyMobileConfirmDialog<T>(
BuildContext context, {
String? title,
String? content,
required String actionButtonTitle,
Color? actionButtonColor,
String? cancelButtonTitle,
required void Function()? onActionButtonPressed,
void Function()? onCancelButtonPressed,
}) async {
return showDialog(
context: context,
builder: (dialogContext) {
final foregroundColor = Theme.of(context).colorScheme.onSurface;
return AlertDialog(
title: Text(
title ?? "",
),
content: Text(
content ?? "",
),
actions: [
TextButton(
child: Text(
actionButtonTitle,
style: TextStyle(
color: actionButtonColor ?? foregroundColor,
),
),
onPressed: () {
onActionButtonPressed?.call();
// we cannot use dialogContext.pop() here because this is no GoRouter in dialogContext. Use Navigator instead to close the dialog.
Navigator.of(
dialogContext,
).pop();
},
),
TextButton(
child: Text(
cancelButtonTitle ?? LocaleKeys.button_cancel.tr(),
style: TextStyle(
color: foregroundColor,
),
),
onPressed: () {
onCancelButtonPressed?.call();
Navigator.of(
dialogContext,
).pop();
},
),
],
);
},
);
}

View File

@ -0,0 +1,3 @@
export 'show_flowy_mobile_confirm_dialog.dart';
export 'show_flowy_mobile_bottom_sheet.dart';
export 'flowy_mobile_state_container.dart';

View File

@ -120,7 +120,9 @@
"mobile": {
"actions": "Trash Actions",
"empty": "Trash Bin is Empty",
"emptyDescription": "You don't have any deleted file"
"emptyDescription": "You don't have any deleted file",
"isDeleted": "is deleted",
"isRestored": "is restored"
}
},
"deletePagePrompt": {
@ -394,7 +396,9 @@
"support": "Support",
"joinDiscord": "Join us in Discord",
"privacyPolicy": "Privacy Policy",
"userAgreement": "User Agreement"
"userAgreement": "User Agreement",
"userprofileError": "Failed to load user profile",
"userprofileErrorDescription": "Please try to log out and log back in to check if the issue still persists."
}
},
"grid": {