diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart index 4027605649..b91a29b7c4 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/card/card_detail/mobile_card_detail_screen.dart @@ -142,7 +142,7 @@ class _MobileRowDetailPageState extends State { showMobileBottomSheet( context, backgroundColor: Theme.of(context).colorScheme.background, - padding: const EdgeInsets.only(top: 8, bottom: 36), + padding: const EdgeInsets.only(top: 8, bottom: 38), builder: (_) => Column( mainAxisSize: MainAxisSize.min, children: [ diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_bottom_sheets.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_bottom_sheets.dart index 876a35fee9..d6fb701706 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_bottom_sheets.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_bottom_sheets.dart @@ -1,4 +1,5 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; +import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_info.dart'; import 'package:appflowy/plugins/database_view/application/field/field_service.dart'; import 'package:flutter/material.dart'; @@ -6,6 +7,7 @@ import 'package:go_router/go_router.dart'; import 'mobile_create_field_screen.dart'; import 'mobile_edit_field_screen.dart'; +import 'mobile_field_picker_list.dart'; import 'mobile_field_type_grid.dart'; import 'mobile_field_type_option_editor.dart'; import 'mobile_quick_field_editor.dart'; @@ -104,3 +106,22 @@ void showQuickEditField( }, ); } + +Future showFieldPicker( + BuildContext context, + String? selectedFieldId, + FieldController fieldController, + bool Function(FieldInfo fieldInfo) filterBy, +) { + return showMobileBottomSheet( + context, + padding: EdgeInsets.zero, + builder: (context) { + return MobileFieldPickerList( + selectedFieldId: selectedFieldId, + fieldController: fieldController, + filterBy: filterBy, + ); + }, + ); +} diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_picker_list.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_picker_list.dart new file mode 100644 index 0000000000..934836a757 --- /dev/null +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_field_picker_list.dart @@ -0,0 +1,150 @@ +import 'package:appflowy/generated/flowy_svgs.g.dart'; +import 'package:appflowy/generated/locale_keys.g.dart'; +import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart'; +import 'package:appflowy/plugins/base/drag_handler.dart'; +import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; +import 'package:appflowy/plugins/database_view/application/field/field_info.dart'; +import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.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'; + +class MobileFieldPickerList extends StatefulWidget { + MobileFieldPickerList({ + super.key, + required this.selectedFieldId, + required FieldController fieldController, + required bool Function(FieldInfo fieldInfo) filterBy, + }) : fields = fieldController.fieldInfos.where(filterBy).toList(); + + final String? selectedFieldId; + final List fields; + + @override + State createState() => _MobileFieldPickerListState(); +} + +class _MobileFieldPickerListState extends State { + String? newFieldId; + + @override + void initState() { + super.initState(); + newFieldId = widget.selectedFieldId; + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const Center(child: DragHandler()), + _Header(newFieldId: newFieldId), + Expanded( + child: ListView.builder( + itemCount: widget.fields.length, + itemBuilder: (context, index) => _FieldButton( + field: widget.fields[index], + showTopBorder: index == 0, + isSelected: widget.fields[index].id == newFieldId, + onSelect: (fieldId) => setState(() => newFieldId = fieldId), + ), + ), + ), + ], + ); + } +} + +class _Header extends StatelessWidget { + const _Header({required this.newFieldId}); + + final String? newFieldId; + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox.square( + dimension: 36, + child: IconButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + padding: EdgeInsets.zero, + onPressed: () => context.pop(), + icon: const FlowySvg( + FlowySvgs.arrow_left_s, + size: Size.square(20), + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 8, 8), + child: TextButton( + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 5, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 0, + visualDensity: VisualDensity.compact, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + enableFeedback: true, + backgroundColor: Theme.of(context).primaryColor, + ), + onPressed: () => context.pop(newFieldId), + child: FlowyText.medium( + LocaleKeys.button_save.tr(), + fontSize: 16, + color: Theme.of(context).colorScheme.onPrimary, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ), + Center( + child: FlowyText.medium( + LocaleKeys.calendar_settings_changeLayoutDateField.tr(), + fontSize: 16, + ), + ), + ], + ); + } +} + +class _FieldButton extends StatelessWidget { + const _FieldButton({ + required this.field, + required this.isSelected, + required this.onSelect, + required this.showTopBorder, + }); + + final FieldInfo field; + final bool isSelected; + final void Function(String fieldId) onSelect; + final bool showTopBorder; + + @override + Widget build(BuildContext context) { + return FlowyOptionTile.checkbox( + text: field.name, + isSelected: isSelected, + leftIcon: FlowySvg( + field.fieldType.icon(), + size: const Size.square(20), + ), + showTopBorder: showTopBorder, + onTap: () => onSelect(field.id), + ); + } +} diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart index b9143788d9..562853b06f 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/field/mobile_quick_field_editor.dart @@ -134,7 +134,7 @@ class _QuickEditFieldState extends State { }, ), ], - const VSpace(12), + const VSpace(38), ], ); } diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_field_list.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_field_list.dart index 80fb33efec..f24f2fe4bb 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_field_list.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_field_list.dart @@ -10,6 +10,7 @@ import 'package:appflowy/plugins/database_view/application/field/field_info.dart import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/widgets/header/field_type_extension.dart'; import 'package:appflowy/plugins/database_view/widgets/setting/field_visibility_extension.dart'; +import 'package:appflowy/workspace/application/view/view_bloc.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart'; import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -23,11 +24,9 @@ class MobileDatabaseFieldList extends StatelessWidget { const MobileDatabaseFieldList({ super.key, required this.databaseController, - required this.viewPB, }); final DatabaseController databaseController; - final ViewPB viewPB; @override Widget build(BuildContext context) { @@ -46,7 +45,7 @@ class MobileDatabaseFieldList extends StatelessWidget { child: SingleChildScrollView( child: _MobileDatabaseFieldListBody( databaseController: databaseController, - view: viewPB, + view: context.read().state.view, ), ), ), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_layout.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_layout.dart index c7dd66238f..70a654a3cc 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_layout.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_layout.dart @@ -2,11 +2,16 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; +import 'package:appflowy/plugins/database_view/application/field/field_info.dart'; +import 'package:appflowy/plugins/database_view/calendar/application/calendar_setting_bloc.dart'; import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_bloc/flutter_bloc.dart'; + +import '../field/mobile_field_bottom_sheets.dart'; /// [DatabaseViewLayoutPicker] is seen when changing the layout type of a /// database view or creating a new database view. @@ -46,6 +51,9 @@ class DatabaseViewLayoutPicker extends StatelessWidget { } } +/// [MobileCalendarViewLayoutSettings] is used when the database layout is +/// calendar. It allows changing the field being used to layout the events, +/// and which day of the week the calendar starts on. class MobileCalendarViewLayoutSettings extends StatelessWidget { const MobileCalendarViewLayoutSettings({ super.key, @@ -56,26 +64,36 @@ class MobileCalendarViewLayoutSettings extends StatelessWidget { @override Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - _layoutField(), - _divider(), - ..._startWeek(context), - ], + return BlocProvider( + create: (context) { + return CalendarSettingBloc( + databaseController: databaseController, + )..add(const CalendarSettingEvent.initial()); + }, + child: BlocBuilder( + builder: (context, state) { + if (state.layoutSetting == null) { + return const SizedBox.shrink(); + } + return Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _CalendarLayoutField( + context: context, + databaseController: databaseController, + selectedFieldId: state.layoutSetting?.fieldId, + ), + _divider(), + ..._startWeek(context, state.layoutSetting?.firstDayOfWeek), + ], + ); + }, + ), ); } - Widget _layoutField() { - return FlowyOptionTile.text( - text: LocaleKeys.calendar_settings_layoutDateField.tr(), - ); - } - - Widget _divider() => const VSpace(20); - - List _startWeek(BuildContext context) { + List _startWeek(BuildContext context, int? firstDayOfWeek) { final symbols = DateFormat.EEEE(context.locale.toLanguageTag()).dateSymbols; return [ Padding( @@ -87,18 +105,85 @@ class MobileCalendarViewLayoutSettings extends StatelessWidget { ), ), FlowyOptionTile.checkbox( - text: symbols.WEEKDAYS[-1], - isSelected: true, - onTap: () {}, + text: symbols.WEEKDAYS[0], + isSelected: firstDayOfWeek! == 0, + onTap: () { + context.read().add( + const CalendarSettingEvent.updateLayoutSetting( + firstDayOfWeek: 0, + ), + ); + }, ), FlowyOptionTile.checkbox( - text: symbols.WEEKDAYS[0], - isSelected: false, + text: symbols.WEEKDAYS[1], + isSelected: firstDayOfWeek == 1, showTopBorder: false, - onTap: () {}, + onTap: () { + context.read().add( + const CalendarSettingEvent.updateLayoutSetting( + firstDayOfWeek: 1, + ), + ); + }, ), ]; } + + Widget _divider() => const VSpace(20); +} + +class _CalendarLayoutField extends StatelessWidget { + const _CalendarLayoutField({ + required this.context, + required this.databaseController, + required this.selectedFieldId, + }); + + final BuildContext context; + final DatabaseController databaseController; + final String? selectedFieldId; + + @override + Widget build(BuildContext context) { + FieldInfo? selectedField; + if (selectedFieldId != null) { + selectedField = + databaseController.fieldController.getField(selectedFieldId!); + } + return FlowyOptionTile.text( + text: LocaleKeys.calendar_settings_layoutDateField.tr(), + trailing: selectedFieldId == null + ? null + : Row( + children: [ + FlowyText( + selectedField!.name, + color: Theme.of(context).hintColor, + ), + const HSpace(8), + const FlowySvg(FlowySvgs.arrow_right_s), + ], + ), + onTap: () async { + final newFieldId = await showFieldPicker( + context, + selectedFieldId, + databaseController.fieldController, + (field) => field.fieldType == FieldType.DateTime, + ); + if (context.mounted && + newFieldId != null && + newFieldId != selectedFieldId) { + context.read().add( + CalendarSettingEvent.updateLayoutSetting( + layoutFieldId: newFieldId, + ), + ); + } + }, + ); + } } class MobileBoardViewLayoutSettings extends StatelessWidget { diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_list.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_list.dart index f2e6896bcb..67951bb542 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_list.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_list.dart @@ -1,30 +1,46 @@ 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/plugins/base/emoji/emoji_text.dart'; -import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart'; +import 'package:appflowy/plugins/base/drag_handler.dart'; +import 'package:appflowy/plugins/database_view/application/database_controller.dart'; +import 'package:appflowy/plugins/database_view/application/tab_bar_bloc.dart'; +import 'package:appflowy/workspace/application/view/view_bloc.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart'; +import 'package:collection/collection.dart'; import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra_ui/widget/spacing.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'; import 'database_view_layout.dart'; +import 'database_view_quick_actions.dart'; /// [MobileDatabaseViewList] shows a list of all the views in the database and /// adds a button to create a new database view. class MobileDatabaseViewList extends StatelessWidget { - const MobileDatabaseViewList({super.key, required this.views}); + const MobileDatabaseViewList({super.key, required this.databaseController}); - final List views; + final DatabaseController databaseController; @override Widget build(BuildContext context) { - return Builder( - builder: (context) { + return BlocBuilder( + builder: (context, state) { + final views = [state.view, ...state.view.childViews]; final children = [ - ...views.map((view) => MobileDatabaseViewListButton(view: view)), + const Center(child: DragHandler()), + const _Header(), + ...views.mapIndexed( + (index, view) => MobileDatabaseViewListButton( + view: view, + databaseController: databaseController, + showTopBorder: index == 0, + ), + ), const VSpace(20), const MobileNewDatabaseViewButton(), ]; @@ -37,36 +53,123 @@ class MobileDatabaseViewList extends StatelessWidget { } } -@visibleForTesting -class MobileDatabaseViewListButton extends StatelessWidget { - const MobileDatabaseViewListButton({super.key, required this.view}); - - final ViewPB view; +class _Header extends StatelessWidget { + const _Header(); @override Widget build(BuildContext context) { - return FlowyOptionTile.text( - text: view.name, - onTap: () {}, - leftIcon: _buildViewIconButton(context, view), - trailing: FlowySvg( - FlowySvgs.three_dots_s, - size: const Size.square(20), - color: Theme.of(context).hintColor, + 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), + ), + width: iconWidth, + iconPadding: EdgeInsets.zero, + onPressed: () => context.pop(), + ), + ), + Align( + alignment: Alignment.center, + child: FlowyText.medium( + LocaleKeys.grid_settings_viewList.tr(), + fontSize: 16, + ), + ), + ], ), ); } +} + +@visibleForTesting +class MobileDatabaseViewListButton extends StatelessWidget { + const MobileDatabaseViewListButton({ + super.key, + required this.view, + required this.databaseController, + required this.showTopBorder, + }); + + final ViewPB view; + final DatabaseController databaseController; + final bool showTopBorder; + + @override + Widget build(BuildContext context) { + return BlocBuilder( + builder: (context, state) { + final index = + state.tabBars.indexWhere((tabBar) => tabBar.viewId == view.id); + final isSelected = index == state.selectedIndex; + return FlowyOptionTile.text( + text: view.name, + onTap: () { + context + .read() + .add(DatabaseTabBarEvent.selectView(view.id)); + }, + leftIcon: _buildViewIconButton(context, view), + trailing: _trailing(context, isSelected), + showTopBorder: showTopBorder, + ); + }, + ); + } Widget _buildViewIconButton(BuildContext context, ViewPB view) { - return view.icon.value.isNotEmpty - ? EmojiText( - emoji: view.icon.value, - fontSize: 16.0, - ) - : SizedBox.square( - dimension: 20.0, - child: view.defaultIcon(), - ); + return SizedBox.square( + dimension: 20.0, + child: view.defaultIcon(), + ); + } + + Widget _trailing(BuildContext context, bool isSelected) { + final more = FlowyIconButton( + icon: FlowySvg( + FlowySvgs.three_dots_s, + size: const Size.square(20), + color: Theme.of(context).hintColor, + ), + onPressed: () { + showMobileBottomSheet( + context, + padding: EdgeInsets.zero, + builder: (_) { + return BlocProvider( + create: (_) => + ViewBloc(view: view)..add(const ViewEvent.initial()), + child: MobileDatabaseViewQuickActions( + view: view, + databaseController: databaseController, + ), + ); + }, + ); + }, + ); + if (isSelected) { + return Row( + mainAxisSize: MainAxisSize.min, + children: [ + const FlowySvg( + FlowySvgs.blue_check_s, + size: Size.square(20), + blendMode: BlendMode.dst, + ), + const HSpace(8), + more, + ], + ); + } else { + return more; + } } } @@ -83,12 +186,20 @@ class MobileNewDatabaseViewButton extends StatelessWidget { size: const Size.square(20), color: Theme.of(context).hintColor, ), - trailing: FlowySvg( - FlowySvgs.three_dots_s, - size: const Size.square(20), - color: Theme.of(context).hintColor, - ), - onTap: () {}, + onTap: () async { + final result = await showMobileBottomSheet<(DatabaseLayoutPB, String)>( + context, + padding: EdgeInsets.zero, + builder: (_) { + return const MobileCreateDatabaseView(); + }, + ); + if (context.mounted && result != null) { + context + .read() + .add(DatabaseTabBarEvent.createView(result.$1, result.$2)); + } + }, ); } } @@ -104,13 +215,13 @@ class MobileCreateDatabaseView extends StatefulWidget { class _MobileCreateDatabaseViewState extends State { late final TextEditingController controller; DatabaseLayoutPB layoutType = DatabaseLayoutPB.Grid; - String icon = ""; @override void initState() { super.initState(); - controller = - TextEditingController(text: LocaleKeys.grid_title_placeholder.tr()); + controller = TextEditingController( + text: LocaleKeys.grid_title_placeholder.tr(), + ); } @override @@ -123,42 +234,93 @@ class _MobileCreateDatabaseViewState extends State { Widget build(BuildContext context) { return Column( children: [ + const Center(child: DragHandler()), + _CreateViewHeader( + textController: controller, + selectedLayout: layoutType, + ), FlowyOptionTile.textField( controller: controller, - leftIcon: _buildViewIcon(), ), const VSpace(20), DatabaseViewLayoutPicker( - selectedLayout: DatabaseLayoutPB.Grid, - onSelect: (layout) {}, + selectedLayout: layoutType, + onSelect: (layout) { + setState(() => layoutType = layout); + }, ), ], ); } +} - Widget _buildViewIcon() { - final viewIcon = icon.isNotEmpty - ? EmojiText( - emoji: icon, - fontSize: 16.0, - ) - : SizedBox.square( - dimension: 18.0, - child: FlowySvg(layoutType.icon), - ); - return InkWell( - onTap: () {}, - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(12)), - border: Border.fromBorderSide( - BorderSide(color: Theme.of(context).dividerColor), +class _CreateViewHeader extends StatelessWidget { + const _CreateViewHeader({ + required this.textController, + required this.selectedLayout, + }); + + final TextEditingController textController; + final DatabaseLayoutPB selectedLayout; + + @override + Widget build(BuildContext context) { + return Stack( + alignment: Alignment.center, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + SizedBox.square( + dimension: 36, + child: IconButton( + highlightColor: Colors.transparent, + splashColor: Colors.transparent, + padding: EdgeInsets.zero, + onPressed: () => context.pop(), + icon: const FlowySvg( + FlowySvgs.arrow_left_s, + size: Size.square(20), + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(8, 4, 8, 8), + child: TextButton( + style: TextButton.styleFrom( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 5, + ), + shape: RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), + ), + elevation: 0, + visualDensity: VisualDensity.compact, + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + enableFeedback: true, + backgroundColor: Theme.of(context).primaryColor, + ), + onPressed: () { + context.pop((selectedLayout, textController.text.trim())); + }, + child: FlowyText.medium( + LocaleKeys.button_done.tr(), + fontSize: 16, + color: Theme.of(context).colorScheme.onPrimary, + overflow: TextOverflow.ellipsis, + ), + ), + ), + ], + ), + Center( + child: FlowyText.medium( + LocaleKeys.grid_settings_createView.tr(), + fontSize: 16, ), ), - width: 36, - height: 36, - child: Center(child: viewIcon), - ), + ], ); } } diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart index 827ab6f59e..1282ea743d 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/database_view_quick_actions.dart @@ -1,34 +1,69 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart'; +import 'package:appflowy/plugins/database_view/application/database_controller.dart'; +import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flutter/material.dart'; +import 'edit_database_view_screen.dart'; + /// [MobileDatabaseViewQuickActions] is gives users to quickly edit a database /// view from the [MobileDatabaseViewList] -class MobileDatabaseViewQuickActions extends StatelessWidget { - const MobileDatabaseViewQuickActions({super.key}); +class MobileDatabaseViewQuickActions extends StatefulWidget { + const MobileDatabaseViewQuickActions({ + super.key, + required this.view, + required this.databaseController, + }); + + final ViewPB view; + final DatabaseController databaseController; + + @override + State createState() => + _MobileDatabaseViewQuickActionsState(); +} + +class _MobileDatabaseViewQuickActionsState + extends State { + bool isEditing = false; @override Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - _actionButton(_Action.edit), - _divider(), - _actionButton(_Action.duplicate), - _divider(), - _actionButton(_Action.delete), - _divider(), - ], - ); + return isEditing + ? MobileEditDatabaseViewScreen( + databaseController: widget.databaseController, + ) + : Padding( + padding: const EdgeInsets.only(top: 8, bottom: 38), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + _actionButton(context, _Action.edit), + _divider(), + _actionButton(context, _Action.duplicate), + _divider(), + _actionButton(context, _Action.delete), + _divider(), + ], + ), + ); } - Widget _actionButton(_Action action) { - return MobileQuickActionButton( - icon: action.icon, - text: action.label, - onTap: () {}, + Widget _actionButton(BuildContext context, _Action action) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 8.0), + child: MobileQuickActionButton( + icon: action.icon, + text: action.label, + color: action.color(context), + onTap: () { + if (action == _Action.edit) { + setState(() => isEditing = true); + } + }, + ), ); } @@ -50,7 +85,7 @@ enum _Action { FlowySvgData get icon { return switch (this) { - edit => FlowySvgs.grid_s, + edit => FlowySvgs.edit_s, duplicate => FlowySvgs.copy_s, delete => FlowySvgs.delete_s, }; diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/edit_database_view_screen.dart b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/edit_database_view_screen.dart index 1bd930ff48..8e23ffe275 100644 --- a/frontend/appflowy_flutter/lib/mobile/presentation/database/view/edit_database_view_screen.dart +++ b/frontend/appflowy_flutter/lib/mobile/presentation/database/view/edit_database_view_screen.dart @@ -3,13 +3,11 @@ import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/widgets/flowy_option_tile.dart'; import 'package:appflowy/plugins/base/drag_handler.dart'; -import 'package:appflowy/plugins/base/emoji/emoji_text.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/application/database_view_service.dart'; import 'package:appflowy/plugins/database_view/application/layout/layout_service.dart'; import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart'; import 'package:appflowy/workspace/application/view/view_bloc.dart'; -import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:appflowy_backend/protobuf/flowy-folder2/protobuf.dart'; import 'package:easy_localization/easy_localization.dart'; @@ -29,11 +27,9 @@ class MobileEditDatabaseViewScreen extends StatefulWidget { const MobileEditDatabaseViewScreen({ super.key, required this.databaseController, - required this.viewPB, }); final DatabaseController databaseController; - final ViewPB viewPB; @override State createState() => @@ -52,13 +48,11 @@ class _MobileEditDatabaseViewScreenState return switch (state.currentPage) { MobileEditDatabaseViewPageEnum.main => _EditDatabaseViewMainPage( databaseController: widget.databaseController, - viewPB: widget.viewPB, ), MobileEditDatabaseViewPageEnum.fields => _wrapSubPage( context, MobileDatabaseFieldList( databaseController: widget.databaseController, - viewPB: widget.viewPB, ), ), _ => const SizedBox.shrink(), @@ -84,11 +78,9 @@ class _MobileEditDatabaseViewScreenState class _EditDatabaseViewMainPage extends StatelessWidget { const _EditDatabaseViewMainPage({ required this.databaseController, - required this.viewPB, }); final DatabaseController databaseController; - final ViewPB viewPB; @override Widget build(BuildContext context) { @@ -107,7 +99,6 @@ class _EditDatabaseViewMainPage extends StatelessWidget { child: SingleChildScrollView( child: _EditDatabaseViewBody( databaseController: databaseController, - view: viewPB, ), ), ), @@ -157,41 +148,40 @@ class _EditDatabaseViewHeader extends StatelessWidget { class _EditDatabaseViewBody extends StatelessWidget { const _EditDatabaseViewBody({ required this.databaseController, - required this.view, }); final DatabaseController databaseController; - final ViewPB view; @override Widget build(BuildContext context) { - return BlocProvider( - create: (context) { - return ViewBloc(view: view)..add(const ViewEvent.initial()); + return BlocBuilder( + builder: (context, state) { + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + _NameAndIcon(view: state.view), + _divider(), + DatabaseViewSettingTile( + setting: DatabaseViewSettings.layout, + databaseController: databaseController, + view: state.view, + showTopBorder: true, + ), + if (databaseController.databaseLayout == DatabaseLayoutPB.Calendar) + DatabaseViewSettingTile( + setting: DatabaseViewSettings.calendar, + databaseController: databaseController, + view: state.view, + ), + DatabaseViewSettingTile( + setting: DatabaseViewSettings.fields, + databaseController: databaseController, + view: state.view, + ), + _divider(), + ], + ); }, - child: BlocBuilder( - builder: (context, state) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - _NameAndIcon(view: state.view), - _divider(), - DatabaseViewSettingTile( - setting: DatabaseViewSettings.layout, - databaseController: databaseController, - view: state.view, - showTopBorder: true, - ), - DatabaseViewSettingTile( - setting: DatabaseViewSettings.fields, - databaseController: databaseController, - view: state.view, - ), - _divider(), - ], - ); - }, - ), ); } @@ -220,37 +210,9 @@ class _NameAndIconState extends State<_NameAndIcon> { Widget build(BuildContext context) { return FlowyOptionTile.textField( controller: textEditingController, - textFieldPadding: const EdgeInsets.symmetric(horizontal: 12.0), onTextChanged: (text) { context.read().add(ViewEvent.rename(text)); }, - leftIcon: _buildViewIcon(), - ); - } - - Widget _buildViewIcon() { - final icon = widget.view.icon.value.isNotEmpty - ? EmojiText( - emoji: widget.view.icon.value, - fontSize: 16.0, - ) - : SizedBox.square( - dimension: 18.0, - child: widget.view.defaultIcon(), - ); - return InkWell( - onTap: () {}, - child: Container( - decoration: BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(12)), - border: Border.fromBorderSide( - BorderSide(color: Theme.of(context).dividerColor), - ), - ), - width: 36, - height: 36, - child: Center(child: icon), - ), ); } } @@ -351,7 +313,8 @@ class DatabaseViewSettingTile extends StatelessWidget { return Row( children: [ FlowyText( - "$numVisible shown", + LocaleKeys.grid_settings_numberOfVisibleFields + .tr(args: [numVisible.toString()]), color: Theme.of(context).hintColor, ), const HSpace(8), diff --git a/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart b/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart deleted file mode 100644 index e246169295..0000000000 --- a/frontend/appflowy_flutter/lib/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart +++ /dev/null @@ -1,227 +0,0 @@ -import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart'; -import 'package:flowy_infra_ui/widget/spacing.dart'; -import 'package:flutter/material.dart'; -import 'package:go_router/go_router.dart'; - -class SheetPage { - const SheetPage({ - required this.title, - required this.body, - }); - - final String title; - final Widget body; -} - -void showPaginatedBottomSheet(BuildContext context, {required SheetPage page}) { - showMobileBottomSheet( - context, - // Workaround for not causing drag to rebuild - isDragEnabled: false, - builder: (context) => FlowyBottomSheet(root: page), - ); -} - -typedef SheetNotifier = ValueNotifier<(SheetPage, bool)>; - -class FlowyBottomSheet extends StatelessWidget { - FlowyBottomSheet({ - super.key, - required this.root, - }) : _notifier = ValueNotifier((root, true)); - - final SheetPage root; - final SheetNotifier _notifier; - - @override - Widget build(BuildContext context) { - return FlowyBottomSheetController( - key: UniqueKey(), - root: root, - onPageChanged: (page, isRoot) => _notifier.value = (page, isRoot), - child: _FlowyBottomSheetHandler( - root: root, - notifier: _notifier, - ), - ); - } -} - -class _FlowyBottomSheetHandler extends StatefulWidget { - const _FlowyBottomSheetHandler({ - required this.root, - required this.notifier, - }); - - final SheetPage root; - final ValueNotifier<(SheetPage, bool)> notifier; - - @override - State<_FlowyBottomSheetHandler> createState() => - _FlowyBottomSheetHandlerState(); -} - -class _FlowyBottomSheetHandlerState extends State<_FlowyBottomSheetHandler> { - late SheetPage currentPage; - late bool isRoot; - - @override - void initState() { - super.initState(); - widget.notifier.addListener(_onPageChanged); - isRoot = true; - currentPage = widget.root; - - WidgetsBinding.instance.addPostFrameCallback((_) { - currentPage = FlowyBottomSheetController.of(context)!.currentPage; - }); - } - - @override - void dispose() { - widget.notifier.removeListener(_onPageChanged); - super.dispose(); - } - - void _onPageChanged() { - final (page, root) = widget.notifier.value; - - if (mounted) { - setState(() { - currentPage = page; - isRoot = root; - }); - } - } - - @override - Widget build(BuildContext context) { - return AnimatedSize( - duration: const Duration(milliseconds: 150), - child: FlowyBottomSheetPage( - isRoot: isRoot, - title: currentPage.title, - child: currentPage.body, - ), - ); - } -} - -class FlowyBottomSheetPage extends StatelessWidget { - const FlowyBottomSheetPage({ - super.key, - required this.title, - required this.child, - this.isRoot = false, - }); - - final String title; - final Widget child; - final bool isRoot; - - @override - Widget build(BuildContext context) { - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - _SheetTopBar(title: title, isRoot: isRoot), - child, - ], - ); - } -} - -class _SheetTopBar extends StatelessWidget { - const _SheetTopBar({ - required this.title, - this.isRoot = false, - }); - - final String title; - final bool isRoot; - - @override - Widget build(BuildContext context) { - final theme = Theme.of(context); - - return Row( - children: [ - if (!isRoot) ...[ - IconButton( - onPressed: () => FlowyBottomSheetController.of(context)!.pop(), - icon: const Icon(Icons.arrow_back_ios), - ), - const HSpace(6), - ], - Text( - title, - style: theme.textTheme.labelSmall, - ), - const Spacer(), - IconButton( - icon: Icon( - Icons.close, - color: theme.hintColor, - ), - onPressed: () => context.pop(), - ), - ], - ); - } -} - -class FlowyBottomSheetController extends InheritedWidget { - FlowyBottomSheetController({ - super.key, - required SheetPage root, - this.onPageChanged, - required super.child, - FlowyBottomSheetControllerImpl? controller, - }) : _controller = controller ?? FlowyBottomSheetControllerImpl(root: root); - - final Function(SheetPage page, bool isRoot)? onPageChanged; - - final FlowyBottomSheetControllerImpl _controller; - SheetPage get currentPage => _controller.page; - - @override - bool updateShouldNotify(covariant FlowyBottomSheetController oldWidget) { - return child != oldWidget.child || - _controller.length != oldWidget._controller.length; - } - - static FlowyBottomSheetController? of(BuildContext context) { - return context - .dependOnInheritedWidgetOfExactType(); - } - - void push(SheetPage page) { - _controller.push(page); - onPageChanged?.call(_controller.page, _controller.isRoot); - } - - void pop() { - _controller.pop(); - onPageChanged?.call(_controller.page, _controller.isRoot); - } -} - -class FlowyBottomSheetControllerImpl { - FlowyBottomSheetControllerImpl({ - required SheetPage root, - }) : _pages = [root]; - - final List _pages; - SheetPage get page => _pages.last; - bool get isRoot => _pages.length == 1; - - int get length => _pages.length; - - void push(SheetPage page) { - _pages.add(page); - } - - void pop() { - _pages.remove(page); - } -} diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/application/tab_bar_bloc.dart b/frontend/appflowy_flutter/lib/plugins/database_view/application/tab_bar_bloc.dart index dac1deb609..0105d86136 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/application/tab_bar_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/application/tab_bar_bloc.dart @@ -50,8 +50,8 @@ class DatabaseTabBarBloc ); } }, - createView: (layout) { - _createLinkedView(layout.layoutType, layout.layoutName); + createView: (layout, name) { + _createLinkedView(layout.layoutType, name ?? layout.layoutName); }, deleteView: (String viewId) async { final result = await ViewBackendService.delete(viewId: viewId); @@ -209,8 +209,10 @@ class DatabaseTabBarEvent with _$DatabaseTabBarEvent { List childViews, ) = _DidLoadChildViews; const factory DatabaseTabBarEvent.selectView(String viewId) = _DidSelectView; - const factory DatabaseTabBarEvent.createView(DatabaseLayoutPB layout) = - _CreateView; + const factory DatabaseTabBarEvent.createView( + DatabaseLayoutPB layout, + String? name, + ) = _CreateView; const factory DatabaseTabBarEvent.renameView(String viewId, String newName) = _RenameView; const factory DatabaseTabBarEvent.deleteView(String viewId) = _DeleteView; diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart index 1834de9224..79114fd4b6 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/application/calendar_setting_bloc.dart @@ -1,9 +1,10 @@ +import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/application/layout/layout_setting_listener.dart'; import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; import 'package:bloc/bloc.dart'; -import 'package:dartz/dartz.dart'; import 'package:freezed_annotation/freezed_annotation.dart'; +import 'package:protobuf/protobuf.dart'; part 'calendar_setting_bloc.freezed.dart'; @@ -11,29 +12,83 @@ typedef DayOfWeek = int; class CalendarSettingBloc extends Bloc { - final String viewId; + final DatabaseController _databaseController; final DatabaseLayoutSettingListener _listener; CalendarSettingBloc({ - required this.viewId, - required CalendarLayoutSettingPB? layoutSettings, - }) : _listener = DatabaseLayoutSettingListener(viewId), - super(CalendarSettingState.initial(layoutSettings)) { + required DatabaseController databaseController, + }) : _databaseController = databaseController, + _listener = DatabaseLayoutSettingListener(databaseController.viewId), + super( + CalendarSettingState.initial( + databaseController.databaseLayoutSetting?.calendar, + ), + ) { on((event, emit) { event.when( - init: () { + initial: () { _startListening(); }, - performAction: (action) { - emit(state.copyWith(selectedAction: Some(action))); + didUpdateLayoutSetting: (CalendarLayoutSettingPB setting) { + emit(state.copyWith(layoutSetting: layoutSetting)); }, - updateLayoutSetting: (setting) { - emit(state.copyWith(layoutSetting: Some(setting))); + updateLayoutSetting: ( + bool? showWeekends, + bool? showWeekNumbers, + int? firstDayOfWeek, + String? layoutFieldId, + ) { + _updateLayoutSettings( + showWeekends, + showWeekNumbers, + firstDayOfWeek, + layoutFieldId, + emit, + ); }, ); }); } + void _updateLayoutSettings( + bool? showWeekends, + bool? showWeekNumbers, + int? firstDayOfWeek, + String? layoutFieldId, + Emitter emit, + ) { + final currentSetting = state.layoutSetting; + if (currentSetting == null) { + return; + } + currentSetting.freeze(); + final newSetting = currentSetting.rebuild((setting) { + if (showWeekends != null) { + setting.showWeekends = !showWeekends; + } + + if (showWeekNumbers != null) { + setting.showWeekNumbers = !showWeekNumbers; + } + + if (firstDayOfWeek != null) { + setting.firstDayOfWeek = firstDayOfWeek; + } + + if (layoutFieldId != null) { + setting.fieldId = layoutFieldId; + } + }); + + _databaseController.updateLayoutSetting( + calendarLayoutSetting: newSetting, + ); + emit(state.copyWith(layoutSetting: newSetting)); + } + + CalendarLayoutSettingPB? get layoutSetting => + _databaseController.databaseLayoutSetting?.calendar; + void _startListening() { _listener.start( onLayoutChanged: (result) { @@ -42,8 +97,9 @@ class CalendarSettingBloc } result.fold( - (setting) => - add(CalendarSettingEvent.updateLayoutSetting(setting.calendar)), + (setting) => add( + CalendarSettingEvent.didUpdateLayoutSetting(setting.calendar), + ), (r) => Log.error(r), ); }, @@ -57,34 +113,29 @@ class CalendarSettingBloc } } -@freezed -class CalendarSettingEvent with _$CalendarSettingEvent { - const factory CalendarSettingEvent.init() = _Init; - const factory CalendarSettingEvent.performAction( - CalendarSettingAction action, - ) = _PerformAction; - const factory CalendarSettingEvent.updateLayoutSetting( - CalendarLayoutSettingPB setting, - ) = _UpdateLayoutSetting; -} - -enum CalendarSettingAction { - properties, - layout, -} - @freezed class CalendarSettingState with _$CalendarSettingState { const factory CalendarSettingState({ - required Option selectedAction, - required Option layoutSetting, + required CalendarLayoutSettingPB? layoutSetting, }) = _CalendarSettingState; factory CalendarSettingState.initial( CalendarLayoutSettingPB? layoutSettings, - ) => - CalendarSettingState( - selectedAction: none(), - layoutSetting: layoutSettings == null ? none() : Some(layoutSettings), - ); + ) { + return CalendarSettingState(layoutSetting: layoutSettings); + } +} + +@freezed +class CalendarSettingEvent with _$CalendarSettingEvent { + const factory CalendarSettingEvent.initial() = _Initial; + const factory CalendarSettingEvent.didUpdateLayoutSetting( + CalendarLayoutSettingPB setting, + ) = _DidUpdateLayoutSetting; + const factory CalendarSettingEvent.updateLayoutSetting({ + bool? showWeekends, + bool? showWeekNumbers, + int? firstDayOfWeek, + String? layoutFieldId, + }) = _UpdateLayoutSetting; } diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart index 8d9302120f..f18bc4c250 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/calendar_page.dart @@ -1,8 +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.dart'; import 'package:appflowy/mobile/presentation/database/card/card.dart'; import 'package:appflowy/mobile/presentation/presentation.dart'; -import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/widgets/show_flowy_mobile_bottom_sheet.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; @@ -446,15 +446,21 @@ class _UnscheduledEventsButtonState extends State { } void _showUnscheduledEventsMobile(List events) => - showPaginatedBottomSheet( + showMobileBottomSheet( context, - page: SheetPage( - title: LocaleKeys.calendar_settings_unscheduledEventsTitle.tr(), - body: UnscheduleEventsList( - databaseController: widget.databaseController, - unscheduleEvents: events, - ), - ), + builder: (_) { + return Column( + children: [ + FlowyText.medium( + LocaleKeys.calendar_settings_unscheduledEventsTitle.tr(), + ), + UnscheduleEventsList( + databaseController: widget.databaseController, + unscheduleEvents: events, + ), + ], + ); + }, ); } diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart index f8a6ecda6c..29658d37d5 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart @@ -1,6 +1,6 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; +import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart'; import 'package:appflowy/plugins/database_view/calendar/application/calendar_setting_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; @@ -12,30 +12,15 @@ 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:protobuf/protobuf.dart'; - -abstract class ICalendarSetting { - const ICalendarSetting(); - - /// Returns the current layout settings for the calendar view. - CalendarLayoutSettingPB? getLayoutSetting(); - - /// Updates the layout settings for the calendar view. - void updateLayoutSettings(CalendarLayoutSettingPB layoutSettings); -} /// Widget that displays a list of settings that alters the appearance of the /// calendar class CalendarLayoutSetting extends StatefulWidget { - final String viewId; - final FieldController fieldController; - final ICalendarSetting calendarSettingController; + final DatabaseController databaseController; const CalendarLayoutSetting({ - required this.viewId, - required this.fieldController, - required this.calendarSettingController, super.key, + required this.databaseController, }); @override @@ -43,61 +28,64 @@ class CalendarLayoutSetting extends StatefulWidget { } class _CalendarLayoutSettingState extends State { - late final PopoverMutex popoverMutex = PopoverMutex(); + final PopoverMutex popoverMutex = PopoverMutex(); @override Widget build(BuildContext context) { return BlocProvider( - create: (context) => CalendarSettingBloc( - viewId: widget.viewId, - layoutSettings: widget.calendarSettingController.getLayoutSetting(), - )..add(const CalendarSettingEvent.init()), + create: (context) { + return CalendarSettingBloc( + databaseController: widget.databaseController, + )..add(const CalendarSettingEvent.initial()); + }, child: BlocBuilder( builder: (context, state) { - final CalendarLayoutSettingPB? settings = state.layoutSetting - .foldLeft(null, (previous, settings) => settings); + final CalendarLayoutSettingPB? settings = state.layoutSetting; if (settings == null) { return const CircularProgressIndicator(); } - final availableSettings = _availableCalendarSettings(settings); + final bloc = context.read(); final items = availableSettings.map((setting) { switch (setting) { case CalendarLayoutSettingAction.showWeekNumber: return ShowWeekNumber( showWeekNumbers: settings.showWeekNumbers, - onUpdated: (showWeekNumbers) => _updateLayoutSettings( - context, - showWeekNumbers: showWeekNumbers, + onUpdated: (showWeekNumbers) => bloc.add( + CalendarSettingEvent.updateLayoutSetting( + showWeekNumbers: showWeekNumbers, + ), ), ); case CalendarLayoutSettingAction.showWeekends: return ShowWeekends( showWeekends: settings.showWeekends, - onUpdated: (showWeekends) => _updateLayoutSettings( - context, - showWeekends: showWeekends, + onUpdated: (showWeekends) => bloc.add( + CalendarSettingEvent.updateLayoutSetting( + showWeekends: showWeekends, + ), ), ); case CalendarLayoutSettingAction.firstDayOfWeek: return FirstDayOfWeek( firstDayOfWeek: settings.firstDayOfWeek, popoverMutex: popoverMutex, - onUpdated: (firstDayOfWeek) => _updateLayoutSettings( - context, - firstDayOfWeek: firstDayOfWeek, + onUpdated: (firstDayOfWeek) => bloc.add( + CalendarSettingEvent.updateLayoutSetting( + firstDayOfWeek: firstDayOfWeek, + ), ), ); case CalendarLayoutSettingAction.layoutField: return LayoutDateField( - fieldController: widget.fieldController, - viewId: widget.viewId, + databaseController: widget.databaseController, fieldId: settings.fieldId, popoverMutex: popoverMutex, - onUpdated: (fieldId) => _updateLayoutSettings( - context, - layoutFieldId: fieldId, + onUpdated: (fieldId) => bloc.add( + CalendarSettingEvent.updateLayoutSetting( + layoutFieldId: fieldId, + ), ), ); default: @@ -140,59 +128,19 @@ class _CalendarLayoutSettingState extends State { return settings; } - - void _updateLayoutSettings( - BuildContext context, { - bool? showWeekends, - bool? showWeekNumbers, - int? firstDayOfWeek, - String? layoutFieldId, - }) { - CalendarLayoutSettingPB setting = context - .read() - .state - .layoutSetting - .foldLeft(null, (previous, settings) => settings)!; - setting.freeze(); - setting = setting.rebuild((setting) { - if (showWeekends != null) { - setting.showWeekends = !showWeekends; - } - - if (showWeekNumbers != null) { - setting.showWeekNumbers = !showWeekNumbers; - } - - if (firstDayOfWeek != null) { - setting.firstDayOfWeek = firstDayOfWeek; - } - - if (layoutFieldId != null) { - setting.fieldId = layoutFieldId; - } - }); - - context - .read() - .add(CalendarSettingEvent.updateLayoutSetting(setting)); - - widget.calendarSettingController.updateLayoutSettings(setting); - } } class LayoutDateField extends StatelessWidget { const LayoutDateField({ super.key, + required this.databaseController, required this.fieldId, - required this.fieldController, - required this.viewId, required this.popoverMutex, required this.onUpdated, }); + final DatabaseController databaseController; final String fieldId; - final String viewId; - final FieldController fieldController; final PopoverMutex popoverMutex; final Function(String fieldId) onUpdated; @@ -207,8 +155,8 @@ class LayoutDateField extends StatelessWidget { popupBuilder: (context) { return BlocProvider( create: (context) => DatabasePropertyBloc( - viewId: viewId, - fieldController: fieldController, + viewId: databaseController.viewId, + fieldController: databaseController.fieldController, )..add(const DatabasePropertyEvent.initial()), child: BlocBuilder( builder: (context, state) { diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/tab_bar/desktop/tab_bar_header.dart b/frontend/appflowy_flutter/lib/plugins/database_view/tab_bar/desktop/tab_bar_header.dart index b59515fcde..931355c216 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/tab_bar/desktop/tab_bar_header.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/tab_bar/desktop/tab_bar_header.dart @@ -123,7 +123,7 @@ class _DatabaseTabBarState extends State { AddDatabaseViewButton( onTap: (layoutType) async { context.read().add( - DatabaseTabBarEvent.createView(layoutType), + DatabaseTabBarEvent.createView(layoutType, null), ); }, ), diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_layout_selector.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_layout_selector.dart index a1a2811104..e0023ea41c 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_layout_selector.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_layout_selector.dart @@ -1,9 +1,7 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; -import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_item_widget.dart'; import 'package:appflowy/plugins/database_view/application/layout/layout_bloc.dart'; import 'package:appflowy/plugins/database_view/widgets/database_layout_ext.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart'; -import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:flowy_infra/theme_extension.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flutter/material.dart'; @@ -73,36 +71,6 @@ class DatabaseViewLayoutCell extends StatelessWidget { final DatabaseLayoutPB databaseLayout; final void Function(DatabaseLayoutPB) onTap; - @override - Widget build(BuildContext context) { - if (PlatformExtension.isMobile) { - return MobileDatabaseViewLayoutCell( - isSelected: isSelected, - databaseLayout: databaseLayout, - onTap: onTap, - ); - } - - return DesktopDatabaseViewLayoutCell( - isSelected: isSelected, - databaseLayout: databaseLayout, - onTap: onTap, - ); - } -} - -class DesktopDatabaseViewLayoutCell extends StatelessWidget { - const DesktopDatabaseViewLayoutCell({ - super.key, - required this.isSelected, - required this.databaseLayout, - required this.onTap, - }); - - final bool isSelected; - final DatabaseLayoutPB databaseLayout; - final void Function(DatabaseLayoutPB) onTap; - @override Widget build(BuildContext context) { return Padding( @@ -126,31 +94,3 @@ class DesktopDatabaseViewLayoutCell extends StatelessWidget { ); } } - -class MobileDatabaseViewLayoutCell extends StatelessWidget { - const MobileDatabaseViewLayoutCell({ - super.key, - required this.isSelected, - required this.databaseLayout, - required this.onTap, - }); - - final bool isSelected; - final DatabaseLayoutPB databaseLayout; - final void Function(DatabaseLayoutPB) onTap; - - @override - Widget build(BuildContext context) { - return MobileSettingItem( - padding: EdgeInsets.zero, - name: databaseLayout.layoutName, - trailing: isSelected ? const FlowySvg(FlowySvgs.check_s) : null, - leadingIcon: FlowySvg( - databaseLayout.icon, - color: Theme.of(context).iconTheme.color, - size: const Size.square(18), - ), - onTap: () => onTap(databaseLayout), - ); - } -} diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_setting_action.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_setting_action.dart index 7281283fc0..431aa29fa9 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_setting_action.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/database_setting_action.dart @@ -1,17 +1,11 @@ import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/mobile/presentation/setting/widgets/mobile_setting_item_widget.dart'; -import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database_view/widgets/setting/database_layout_selector.dart'; import 'package:appflowy/plugins/database_view/widgets/group/database_group.dart'; -import 'package:appflowy/plugins/database_view/widgets/setting/mobile_calendar_settings.dart'; -import 'package:appflowy/plugins/database_view/widgets/setting/setting_button.dart'; import 'package:appflowy/plugins/database_view/widgets/setting/setting_property_list.dart'; -import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pbenum.dart'; -import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/theme_extension.dart'; @@ -72,130 +66,32 @@ extension DatabaseSettingActionExtension on DatabaseSettingAction { fieldController: databaseController.fieldController, ), DatabaseSettingAction.showCalendarLayout => CalendarLayoutSetting( - viewId: databaseController.viewId, - fieldController: databaseController.fieldController, - calendarSettingController: ICalendarSettingImpl( - databaseController, - ), + databaseController: databaseController, ), }; return AppFlowyPopover( - triggerActions: PlatformExtension.isMobile - ? PopoverTriggerFlags.none - : PopoverTriggerFlags.hover | PopoverTriggerFlags.click, + triggerActions: PopoverTriggerFlags.hover | PopoverTriggerFlags.click, direction: PopoverDirection.leftWithTopAligned, mutex: popoverMutex, margin: EdgeInsets.zero, offset: const Offset(-14, 0), - child: PlatformExtension.isMobile - ? MobileSettingItem( - name: title(), - trailing: _trailingFromSetting( - context, - databaseController.databaseLayout, - ), - leadingIcon: FlowySvg( - iconData(), - size: const Size.square(18), - color: Theme.of(context).iconTheme.color, - ), - onTap: _actionFromSetting(context, databaseController), - ) - : SizedBox( - height: GridSize.popoverItemHeight, - child: FlowyButton( - onTap: null, - hoverColor: AFThemeExtension.of(context).lightGreyHover, - text: FlowyText.medium( - title(), - color: AFThemeExtension.of(context).textColor, - ), - leftIcon: FlowySvg( - iconData(), - color: Theme.of(context).iconTheme.color, - ), - ), - ), + child: SizedBox( + height: GridSize.popoverItemHeight, + child: FlowyButton( + onTap: null, + hoverColor: AFThemeExtension.of(context).lightGreyHover, + text: FlowyText.medium( + title(), + color: AFThemeExtension.of(context).textColor, + ), + leftIcon: FlowySvg( + iconData(), + color: Theme.of(context).iconTheme.color, + ), + ), + ), popupBuilder: (context) => popover, ); } - - VoidCallback? _actionFromSetting( - BuildContext context, - DatabaseController databaseController, - ) => - switch (this) { - DatabaseSettingAction.showLayout => () => - _showLayoutSettings(context, databaseController), - DatabaseSettingAction.showProperties => () => - _showPropertiesSettings(context, databaseController), - DatabaseSettingAction.showCalendarLayout => () => - _showCalendarSettings(context, databaseController), - // Group Settings - _ => null, - }; - - void _showLayoutSettings( - BuildContext context, - DatabaseController databaseController, - ) => - FlowyBottomSheetController.of(context)!.push( - SheetPage( - title: LocaleKeys.settings_mobile_selectLayout.tr(), - body: DatabaseLayoutSelector( - viewId: databaseController.viewId, - currentLayout: databaseController.databaseLayout, - ), - ), - ); - - void _showPropertiesSettings( - BuildContext context, - DatabaseController databaseController, - ) => - FlowyBottomSheetController.of(context)!.push( - SheetPage( - title: LocaleKeys.grid_settings_properties.tr(), - body: DatabasePropertyList( - viewId: databaseController.viewId, - fieldController: databaseController.fieldController, - ), - ), - ); - - void _showCalendarSettings( - BuildContext context, - DatabaseController databaseController, - ) => - FlowyBottomSheetController.of(context)!.push( - SheetPage( - title: LocaleKeys.calendar_settings_name.tr(), - body: MobileCalendarLayoutSetting( - viewId: databaseController.viewId, - fieldController: databaseController.fieldController, - calendarSettingController: ICalendarSettingImpl( - databaseController, - ), - ), - ), - ); - - Widget? _trailingFromSetting(BuildContext context, DatabaseLayoutPB layout) => - switch (this) { - DatabaseSettingAction.showLayout => Row( - mainAxisSize: MainAxisSize.min, - children: [ - FlowyText( - layout.name, - color: Theme.of(context).colorScheme.onSurface, - ), - Icon( - Icons.chevron_right, - color: Theme.of(context).colorScheme.onSurface, - ), - ], - ), - _ => null, - }; } diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_calendar_settings.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_calendar_settings.dart deleted file mode 100644 index be35a5498a..0000000000 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_calendar_settings.dart +++ /dev/null @@ -1,347 +0,0 @@ -import 'package:appflowy/generated/flowy_svgs.g.dart'; -import 'package:appflowy/generated/locale_keys.g.dart'; -import 'package:appflowy/mobile/presentation/presentation.dart'; -import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart'; -import 'package:appflowy/plugins/database_view/application/field/field_controller.dart'; -import 'package:appflowy/plugins/database_view/application/field/field_info.dart'; -import 'package:appflowy/plugins/database_view/application/setting/property_bloc.dart'; -import 'package:appflowy/plugins/database_view/calendar/application/calendar_setting_bloc.dart'; -import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart'; -import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; -import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart'; -import 'package:appflowy_popover/appflowy_popover.dart'; -import 'package:easy_localization/easy_localization.dart'; -import 'package:flowy_infra_ui/flowy_infra_ui.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_bloc/flutter_bloc.dart'; -import 'package:protobuf/protobuf.dart' hide FieldInfo; - -class MobileCalendarLayoutSetting extends StatefulWidget { - const MobileCalendarLayoutSetting({ - super.key, - required this.viewId, - required this.fieldController, - required this.calendarSettingController, - }); - - final String viewId; - final FieldController fieldController; - final ICalendarSetting calendarSettingController; - - @override - State createState() => - _MobileCalendarLayoutSettingState(); -} - -class _MobileCalendarLayoutSettingState - extends State { - late final PopoverMutex popoverMutex = PopoverMutex(); - late final CalendarSettingBloc calendarSettingBloc; - - @override - void initState() { - super.initState(); - calendarSettingBloc = CalendarSettingBloc( - viewId: widget.viewId, - layoutSettings: widget.calendarSettingController.getLayoutSetting(), - )..add(const CalendarSettingEvent.init()); - } - - @override - Widget build(BuildContext context) { - return BlocProvider.value( - value: calendarSettingBloc, - child: BlocBuilder( - builder: (context, state) { - final CalendarLayoutSettingPB? settings = state.layoutSetting - .foldLeft(null, (previous, settings) => settings); - - if (settings == null) { - return const CircularProgressIndicator(); - } - - final availableSettings = _availableCalendarSettings(settings); - final items = availableSettings.map((setting) { - switch (setting) { - case CalendarLayoutSettingAction.firstDayOfWeek: - return MobileFirstDayOfWeekSetting( - selectedDay: settings.firstDayOfWeek, - onUpdated: (firstDayOfWeek) => _updateLayoutSettings( - context, - firstDayOfWeek: firstDayOfWeek, - ), - ); - case CalendarLayoutSettingAction.layoutField: - return MobileLayoutDateField( - fieldController: widget.fieldController, - viewId: widget.viewId, - fieldId: settings.fieldId, - popoverMutex: popoverMutex, - onUpdated: (fieldId) => _updateLayoutSettings( - context, - layoutFieldId: fieldId, - ), - ); - default: - return const SizedBox.shrink(); - } - }).toList(); - - return ListView.separated( - shrinkWrap: true, - itemCount: items.length, - separatorBuilder: (context, index) => - VSpace(GridSize.typeOptionSeparatorHeight), - physics: StyledScrollPhysics(), - itemBuilder: (_, int index) => items[index], - padding: const EdgeInsets.all(6.0), - ); - }, - ), - ); - } - - List _availableCalendarSettings( - CalendarLayoutSettingPB layoutSettings, - ) { - final List settings = [ - CalendarLayoutSettingAction.layoutField, - ]; - - switch (layoutSettings.layoutTy) { - case CalendarLayoutPB.DayLayout: - break; - case CalendarLayoutPB.MonthLayout: - case CalendarLayoutPB.WeekLayout: - settings.add(CalendarLayoutSettingAction.firstDayOfWeek); - break; - } - - return settings; - } - - void _updateLayoutSettings( - BuildContext context, { - bool? showWeekends, - bool? showWeekNumbers, - int? firstDayOfWeek, - String? layoutFieldId, - }) { - CalendarLayoutSettingPB setting = calendarSettingBloc.state.layoutSetting - .foldLeft(null, (previous, settings) => settings)!; - setting.freeze(); - setting = setting.rebuild((setting) { - if (showWeekends != null) { - setting.showWeekends = !showWeekends; - } - if (showWeekNumbers != null) { - setting.showWeekNumbers = !showWeekNumbers; - } - if (firstDayOfWeek != null) { - setting.firstDayOfWeek = firstDayOfWeek; - } - if (layoutFieldId != null) { - setting.fieldId = layoutFieldId; - } - }); - - calendarSettingBloc.add(CalendarSettingEvent.updateLayoutSetting(setting)); - widget.calendarSettingController.updateLayoutSettings(setting); - } -} - -class MobileLayoutDateField extends StatelessWidget { - const MobileLayoutDateField({ - super.key, - required this.fieldId, - required this.fieldController, - required this.viewId, - required this.popoverMutex, - required this.onUpdated, - }); - - final String fieldId; - final String viewId; - final FieldController fieldController; - final PopoverMutex popoverMutex; - final Function(String fieldId) onUpdated; - - @override - Widget build(BuildContext context) { - return BlocProvider( - create: (context) => DatabasePropertyBloc( - viewId: viewId, - fieldController: fieldController, - )..add(const DatabasePropertyEvent.initial()), - child: BlocBuilder( - builder: (context, state) { - final items = state.fieldContexts - .where((field) => field.fieldType == FieldType.DateTime) - .toList(); - final selected = items.firstWhere((field) => field.id == fieldId); - - return MobileSettingItem( - padding: EdgeInsets.zero, - name: LocaleKeys.calendar_settings_layoutDateField.tr(), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: FlowyText( - selected.name, - color: Theme.of(context).colorScheme.onSurface, - ), - ), - const Icon(Icons.chevron_right), - ], - ), - onTap: () => _showSelector(context, items), - ); - }, - ), - ); - } - - void _showSelector(BuildContext context, List items) => - FlowyBottomSheetController.of(context)!.push( - SheetPage( - title: LocaleKeys.settings_mobile_selectStartingDay.tr(), - body: MobileCalendarLayoutSelector( - fieldId: fieldId, - items: items, - onUpdated: onUpdated, - ), - ), - ); -} - -class MobileCalendarLayoutSelector extends StatefulWidget { - const MobileCalendarLayoutSelector({ - super.key, - required this.fieldId, - required this.items, - required this.onUpdated, - }); - - final String fieldId; - final List items; - final Function(String fieldId) onUpdated; - - @override - State createState() => - _MobileCalendarLayoutSelectorState(); -} - -class _MobileCalendarLayoutSelectorState - extends State { - late String _selectedField = widget.fieldId; - - @override - Widget build(BuildContext context) { - return ListView.separated( - shrinkWrap: true, - itemCount: widget.items.length, - separatorBuilder: (_, __) => const VSpace(4), - itemBuilder: (_, index) => MobileSettingItem( - name: widget.items[index].name, - trailing: _selectedField == widget.items[index].id - ? const FlowySvg(FlowySvgs.check_s) - : null, - onTap: () { - final selected = widget.items[index].id; - widget.onUpdated(selected); - setState(() => _selectedField = selected); - }, - ), - ); - } -} - -const weekdayOptions = 2; - -class MobileFirstDayOfWeekSetting extends StatelessWidget { - const MobileFirstDayOfWeekSetting({ - super.key, - required this.selectedDay, - required this.onUpdated, - }); - - final int selectedDay; - final Function(int firstDayOfWeek) onUpdated; - - @override - Widget build(BuildContext context) { - final symbols = DateFormat.EEEE(context.locale.toLanguageTag()).dateSymbols; - final weekdays = symbols.WEEKDAYS.take(weekdayOptions).toList(); - - return MobileSettingItem( - padding: EdgeInsets.zero, - name: LocaleKeys.calendar_settings_firstDayOfWeek.tr(), - trailing: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Flexible( - child: FlowyText( - weekdays[selectedDay], - color: Theme.of(context).colorScheme.onSurface, - ), - ), - const Icon(Icons.chevron_right), - ], - ), - onTap: () => _showSelector(context), - ); - } - - void _showSelector(BuildContext context) => - FlowyBottomSheetController.of(context)!.push( - SheetPage( - title: LocaleKeys.calendar_settings_layoutDateField.tr(), - body: MobileFirstDayOfWeekSelector( - selectedDay: selectedDay, - onUpdated: onUpdated, - ), - ), - ); -} - -class MobileFirstDayOfWeekSelector extends StatefulWidget { - const MobileFirstDayOfWeekSelector({ - super.key, - required this.selectedDay, - required this.onUpdated, - }); - - final int selectedDay; - final Function(int firstDayOfWeek) onUpdated; - - @override - State createState() => - _MobileFirstDayOfWeekSelectorState(); -} - -class _MobileFirstDayOfWeekSelectorState - extends State { - late int _selectedDay = widget.selectedDay; - - @override - Widget build(BuildContext context) { - final symbols = DateFormat.EEEE(context.locale.toLanguageTag()).dateSymbols; - final weekdays = symbols.WEEKDAYS.take(weekdayOptions).toList(); - - return ListView.separated( - shrinkWrap: true, - itemCount: weekdayOptions, - separatorBuilder: (_, __) => const VSpace(4), - itemBuilder: (_, index) => MobileSettingItem( - name: weekdays[index], - trailing: - _selectedDay == index ? const FlowySvg(FlowySvgs.check_s) : null, - onTap: () { - widget.onUpdated(index); - setState(() => _selectedDay = index); - }, - ), - ); - } -} diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_database_controls.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_database_controls.dart index 4b7dd0b3cf..118a94632e 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_database_controls.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/mobile_database_controls.dart @@ -1,15 +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.dart'; +import 'package:appflowy/mobile/presentation/database/view/database_view_list.dart'; import 'package:appflowy/mobile/presentation/database/view/edit_database_view_screen.dart'; -import 'package:appflowy/mobile/presentation/widgets/flowy_paginated_bottom_sheet.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; +import 'package:appflowy/plugins/database_view/application/tab_bar_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/filter/filter_menu_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/application/sort/sort_menu_bloc.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/grid_page.dart'; -import 'package:appflowy/plugins/database_view/widgets/setting/database_settings_list.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'; @@ -66,16 +64,48 @@ class MobileDatabaseControls extends StatelessWidget { showMobileBottomSheet( context, padding: EdgeInsets.zero, - builder: (_) => MobileEditDatabaseViewScreen( - databaseController: controller, - viewPB: context.read().state.view, - ), + builder: (_) { + return BlocProvider( + create: (_) { + return ViewBloc( + view: context + .read() + .state + .tabBarControllerByViewId[controller.viewId]! + .view, + )..add(const ViewEvent.initial()); + }, + child: MobileEditDatabaseViewScreen( + databaseController: controller, + ), + ); + }, ); }, ), _DatabaseControlButton( icon: FlowySvgs.align_left_s, - onTap: () => _showMobileSettings(context, controller), + onTap: () { + showMobileBottomSheet( + context, + padding: EdgeInsets.zero, + builder: (_) { + return MultiBlocProvider( + providers: [ + BlocProvider.value( + value: context.read(), + ), + BlocProvider.value( + value: context.read(), + ), + ], + child: MobileDatabaseViewList( + databaseController: controller, + ), + ); + }, + ); + }, ), ], ); @@ -84,20 +114,6 @@ class MobileDatabaseControls extends StatelessWidget { ), ); } - - void _showMobileSettings( - BuildContext context, - DatabaseController controller, - ) => - showPaginatedBottomSheet( - context, - page: SheetPage( - title: LocaleKeys.settings_title.tr(), - body: DatabaseSettingsList( - databaseController: controller, - ), - ), - ); } class _DatabaseControlButton extends StatelessWidget { @@ -111,9 +127,8 @@ class _DatabaseControlButton extends StatelessWidget { @override Widget build(BuildContext context) { - return SizedBox( - height: 36, - width: 36, + return SizedBox.square( + dimension: 36, child: IconButton( splashRadius: 18, padding: EdgeInsets.zero, diff --git a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart index 6c9a70300b..a677a9638c 100644 --- a/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart +++ b/frontend/appflowy_flutter/lib/plugins/database_view/widgets/setting/setting_button.dart @@ -2,10 +2,8 @@ import 'package:flutter/material.dart'; import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/plugins/database_view/application/database_controller.dart'; -import 'package:appflowy/plugins/database_view/calendar/presentation/toolbar/calendar_layout_setting.dart'; import 'package:appflowy/plugins/database_view/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database_view/widgets/setting/database_settings_list.dart'; -import 'package:appflowy_backend/protobuf/flowy-database2/calendar_entities.pb.dart'; import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:easy_localization/easy_localization.dart'; import 'package:flowy_infra/size.dart'; @@ -52,19 +50,3 @@ class _SettingButtonState extends State { ); } } - -class ICalendarSettingImpl extends ICalendarSetting { - const ICalendarSettingImpl(this._databaseController); - - final DatabaseController _databaseController; - - @override - void updateLayoutSettings(CalendarLayoutSettingPB layoutSettings) => - _databaseController.updateLayoutSetting( - calendarLayoutSetting: layoutSettings, - ); - - @override - CalendarLayoutSettingPB? getLayoutSetting() => - _databaseController.databaseLayoutSetting?.calendar; -} diff --git a/frontend/resources/translations/en.json b/frontend/resources/translations/en.json index 13406f18b7..1af4791660 100644 --- a/frontend/resources/translations/en.json +++ b/frontend/resources/translations/en.json @@ -465,6 +465,7 @@ "typeAValue": "Type a value...", "layout": "Layout", "databaseLayout": "Layout", + "viewList": "Database Views", "editView": "Edit View", "boardSettings": "Board settings", "calendarSettings": "Calendar settings", @@ -911,6 +912,7 @@ "showWeekends": "Show weekends", "firstDayOfWeek": "Start week on", "layoutDateField": "Layout calendar by", + "changeLayoutDateField": "Change layout field", "noDateTitle": "No Date", "noDateHint": { "zero": "Unscheduled events will show up here",