chore: revamp mobile database toolbar (#4579)

* chore: revamp mobile database toolbar

* chore: code cleanup
This commit is contained in:
Richard Shiue 2024-02-04 00:55:44 +08:00 committed by GitHub
parent 8c1d0106dd
commit ca93cb20ec
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 107 additions and 180 deletions

View File

@ -81,6 +81,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
child: Scaffold( child: Scaffold(
appBar: FlowyAppBar( appBar: FlowyAppBar(
leadingType: FlowyAppBarLeadingType.close, leadingType: FlowyAppBarLeadingType.close,
showDivider: false,
actions: [ actions: [
AppBarMoreButton( AppBarMoreButton(
onTap: (_) => _showCardActions(context), onTap: (_) => _showCardActions(context),

View File

@ -22,15 +22,18 @@ class MobileDatabaseFieldList extends StatelessWidget {
const MobileDatabaseFieldList({ const MobileDatabaseFieldList({
super.key, super.key,
required this.databaseController, required this.databaseController,
required this.canCreate,
}); });
final DatabaseController databaseController; final DatabaseController databaseController;
final bool canCreate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return _MobileDatabaseFieldListBody( return _MobileDatabaseFieldListBody(
databaseController: databaseController, databaseController: databaseController,
viewId: context.read<ViewBloc>().state.view.id, viewId: context.read<ViewBloc>().state.view.id,
canCreate: canCreate,
); );
} }
} }
@ -39,10 +42,12 @@ class _MobileDatabaseFieldListBody extends StatelessWidget {
const _MobileDatabaseFieldListBody({ const _MobileDatabaseFieldListBody({
required this.databaseController, required this.databaseController,
required this.viewId, required this.viewId,
required this.canCreate,
}); });
final DatabaseController databaseController; final DatabaseController databaseController;
final String viewId; final String viewId;
final bool canCreate;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -113,13 +118,15 @@ class _MobileDatabaseFieldListBody extends StatelessWidget {
.add(DatabasePropertyEvent.moveField(from, to)); .add(DatabasePropertyEvent.moveField(from, to));
}, },
header: firstCell, header: firstCell,
footer: Column( footer: canCreate
mainAxisSize: MainAxisSize.min, ? Column(
children: [ mainAxisSize: MainAxisSize.min,
_divider(), children: [
_NewDatabaseFieldTile(viewId: viewId), _divider(),
], _NewDatabaseFieldTile(viewId: viewId),
), ],
)
: null,
itemCount: cells.length, itemCount: cells.length,
itemBuilder: (context, index) => cells[index], itemBuilder: (context, index) => cells[index],
); );

View File

@ -240,6 +240,7 @@ class DatabaseViewSettingTile extends StatelessWidget {
value: context.read<ViewBloc>(), value: context.read<ViewBloc>(),
child: MobileDatabaseFieldList( child: MobileDatabaseFieldList(
databaseController: databaseController, databaseController: databaseController,
canCreate: true,
), ),
); );
}, },

View File

@ -1,7 +1,11 @@
import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
import 'package:appflowy/mobile/presentation/database/view/database_view_list.dart';
import 'package:appflowy/plugins/base/emoji/emoji_text.dart'; import 'package:appflowy/plugins/base/emoji/emoji_text.dart';
import 'package:appflowy/plugins/database/application/tab_bar_bloc.dart'; import 'package:appflowy/plugins/database/application/tab_bar_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/widgets/setting/mobile_database_controls.dart'; import 'package:appflowy/plugins/database/widgets/setting/mobile_database_controls.dart';
import 'package:appflowy/workspace/application/view/view_bloc.dart';
import 'package:appflowy/workspace/application/view/view_ext.dart'; import 'package:appflowy/workspace/application/view/view_ext.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
@ -24,10 +28,11 @@ class _MobileTabBarHeaderState extends State<MobileTabBarHeader> {
return Padding( return Padding(
padding: const EdgeInsets.symmetric(vertical: 14), padding: const EdgeInsets.symmetric(vertical: 14),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisAlignment: MainAxisAlignment.spaceBetween,
children: [ children: [
const Expanded(child: _DatabaseViewList()), HSpace(GridSize.leadingHeaderPadding),
const HSpace(10), const _DatabaseViewSelectorButton(),
const Spacer(),
BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>( BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
builder: (context, state) { builder: (context, state) {
final currentView = state.tabBars.firstWhereIndexedOrNull( final currentView = state.tabBars.firstWhereIndexedOrNull(
@ -51,134 +56,80 @@ class _MobileTabBarHeaderState extends State<MobileTabBarHeader> {
} }
} }
class _DatabaseViewList extends StatelessWidget { class _DatabaseViewSelectorButton extends StatelessWidget {
const _DatabaseViewList(); const _DatabaseViewSelectorButton();
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>( return BlocBuilder<DatabaseTabBarBloc, DatabaseTabBarState>(
builder: (context, state) { builder: (context, state) {
final currentView = state.tabBars.firstWhereIndexedOrNull( final tabBar = state.tabBars.firstWhereIndexedOrNull(
(index, tabBar) => index == state.selectedIndex, (index, tabBar) => index == state.selectedIndex,
); );
if (currentView == null) { if (tabBar == null) {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
final children = state.tabBars.mapIndexed<Widget>((index, tabBar) { return TextButton(
return Padding( style: ButtonStyle(
padding: EdgeInsetsDirectional.only( padding: const MaterialStatePropertyAll(
start: index == 0 ? 0 : 2, EdgeInsets.fromLTRB(12, 8, 8, 8),
end: 2,
), ),
child: _DatabaseViewListItem( maximumSize: const MaterialStatePropertyAll(Size(200, 48)),
tabBar: tabBar, minimumSize: const MaterialStatePropertyAll(Size(48, 0)),
isSelected: currentView.viewId == tabBar.viewId, shape: const MaterialStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
), ),
); backgroundColor: const MaterialStatePropertyAll(Color(0x0F212729)),
}).toList(); overlayColor: MaterialStatePropertyAll(
Theme.of(context).colorScheme.secondary,
children.insert(0, HSpace(GridSize.leadingHeaderPadding)); ),
),
return SingleChildScrollView( child: Row(
scrollDirection: Axis.horizontal, mainAxisSize: MainAxisSize.min,
child: Row(children: children), children: [
_buildViewIconButton(context, tabBar.view),
const HSpace(6),
Flexible(
child: FlowyText.medium(
tabBar.view.name,
fontSize: 13,
overflow: TextOverflow.ellipsis,
),
),
const HSpace(8),
const FlowySvg(
FlowySvgs.arrow_tight_s,
size: Size.square(10),
),
],
),
onPressed: () {
showMobileBottomSheet(
context,
showDivider: false,
builder: (_) {
return MultiBlocProvider(
providers: [
BlocProvider<ViewBloc>.value(
value: context.read<ViewBloc>(),
),
BlocProvider<DatabaseTabBarBloc>.value(
value: context.read<DatabaseTabBarBloc>(),
),
],
child: const MobileDatabaseViewList(),
);
},
);
},
); );
}, },
); );
} }
}
class _DatabaseViewListItem extends StatefulWidget {
const _DatabaseViewListItem({
required this.tabBar,
required this.isSelected,
});
final DatabaseTabBar tabBar;
final bool isSelected;
@override
State<_DatabaseViewListItem> createState() => _DatabaseViewListItemState();
}
class _DatabaseViewListItemState extends State<_DatabaseViewListItem> {
late final MaterialStatesController statesController;
@override
void initState() {
super.initState();
statesController = MaterialStatesController(
<MaterialState>{if (widget.isSelected) MaterialState.selected},
);
}
@override
void didUpdateWidget(covariant oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.isSelected != oldWidget.isSelected) {
statesController.update(MaterialState.selected, widget.isSelected);
}
}
@override
Widget build(BuildContext context) {
return TextButton(
statesController: statesController,
style: ButtonStyle(
padding: const MaterialStatePropertyAll(
EdgeInsets.symmetric(horizontal: 12, vertical: 7),
),
maximumSize: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const Size(150, 48);
}
return const Size(120, 48);
}),
minimumSize: const MaterialStatePropertyAll(Size(48, 0)),
shape: const MaterialStatePropertyAll(
RoundedRectangleBorder(
borderRadius: BorderRadius.all(Radius.circular(12)),
),
),
backgroundColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return const Color(0x0F212729);
}
return Colors.transparent;
}),
overlayColor: MaterialStateProperty.resolveWith((states) {
if (states.contains(MaterialState.selected)) {
return Colors.transparent;
}
return Theme.of(context).colorScheme.secondary;
}),
),
child: Row(
mainAxisSize: MainAxisSize.min,
children: [
_buildViewIconButton(context, widget.tabBar.view),
const HSpace(6),
Flexible(
child: FlowyText(
widget.tabBar.view.name,
fontSize: 14,
fontWeight: widget.isSelected ? FontWeight.w500 : FontWeight.w400,
overflow: TextOverflow.ellipsis,
),
),
],
),
onPressed: () {
if (!widget.isSelected) {
context
.read<DatabaseTabBarBloc>()
.add(DatabaseTabBarEvent.selectView(widget.tabBar.viewId));
}
},
);
}
Widget _buildViewIconButton(BuildContext context, ViewPB view) { Widget _buildViewIconButton(BuildContext context, ViewPB view) {
return view.icon.value.isNotEmpty return view.icon.value.isNotEmpty

View File

@ -1,10 +1,8 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.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/database_field_list.dart';
import 'package:appflowy/mobile/presentation/database/view/edit_database_view_screen.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart'; import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/application/tab_bar_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bloc.dart';
import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/sort/sort_menu_bloc.dart';
import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart'; import 'package:appflowy/plugins/database/grid/presentation/grid_page.dart';
@ -58,62 +56,26 @@ class MobileDatabaseControls extends StatelessWidget {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
return Row( return _DatabaseControlButton(
children: [ icon: FlowySvgs.m_field_hide_s,
_DatabaseControlButton( onTap: () => showMobileBottomSheet(
icon: FlowySvgs.settings_s, context,
onTap: () { resizeToAvoidBottomInset: false,
showMobileBottomSheet( showDragHandle: true,
context, showHeader: true,
showHeader: true, showBackButton: true,
showDoneButton: true, title: LocaleKeys.grid_settings_properties.tr(),
title: LocaleKeys.grid_settings_editView.tr(), showDivider: true,
enableDraggableScrollable: true, builder: (_) {
initialChildSize: 0.98, return BlocProvider.value(
minChildSize: 0.98, value: context.read<ViewBloc>(),
maxChildSize: 0.98, child: MobileDatabaseFieldList(
builder: (_) { databaseController: controller,
return BlocProvider<ViewBloc>( canCreate: false,
create: (_) { ),
return ViewBloc( );
view: context },
.read<DatabaseTabBarBloc>() ),
.state
.tabBarControllerByViewId[controller.viewId]!
.view,
)..add(const ViewEvent.initial());
},
child: MobileEditDatabaseViewScreen(
databaseController: controller,
),
);
},
);
},
),
_DatabaseControlButton(
icon: FlowySvgs.align_left_s,
onTap: () {
showMobileBottomSheet(
context,
showDivider: false,
builder: (_) {
return MultiBlocProvider(
providers: [
BlocProvider<ViewBloc>.value(
value: context.read<ViewBloc>(),
),
BlocProvider<DatabaseTabBarBloc>.value(
value: context.read<DatabaseTabBarBloc>(),
),
],
child: const MobileDatabaseViewList(),
);
},
);
},
),
],
); );
}, },
), ),

View File

@ -0,0 +1,5 @@
<svg width="10" height="10" viewBox="0 0 10 10" fill="none" xmlns="http://www.w3.org/2000/svg">
<g opacity="0.9">
<path d="M1.59505 3.16079C1.40444 2.97017 1.0954 2.97017 0.904783 3.16079C0.71417 3.3514 0.71417 3.66044 0.904783 3.85106L4.36016 7.30643C4.71349 7.65976 5.28635 7.65976 5.63968 7.30643L9.09505 3.85106C9.28567 3.66044 9.28567 3.3514 9.09505 3.16079C8.90444 2.97017 8.5954 2.97017 8.40478 3.16079L4.99992 6.56565L1.59505 3.16079Z" fill="#2B2F36" stroke="black" stroke-width="0.142857" stroke-linecap="round" stroke-linejoin="round"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 559 B