fix: 0.3.9 launch review (#4076)

* fix: cursor away doesn’t save the change. This behavior is inconsistent with the rest

* fix: emoji doesn’t show fully

* chore: set the default header text style to bold

* fix: add missing divider in time option

* fix: update placeholder cover color

* fix: background color of the change cover button

* fix: remove redundant padding

* fix: use done action instead of return

* fix: incorrect font size used in board and editor

* feat: update appflowy-editor

* fix: document freeze and the toolbar was invisible when hovering the align icon that in the toolbar

* fix: snackbar text is invisiable

* feat: padding of add icon button should be aligned the block

* chore: update icon

* fix: ci issues

* feat: add time picker
This commit is contained in:
Lucas.Xu 2023-12-05 10:46:17 +08:00 committed by GitHub
parent 0d776a9294
commit 1491fbfb0d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
42 changed files with 380 additions and 210 deletions

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.5 KiB

After

Width:  |  Height:  |  Size: 3.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.5 KiB

After

Width:  |  Height:  |  Size: 8.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 13 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 16 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View File

@ -1,13 +1,14 @@
import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/openai/service/openai_client.dart';
import 'package:appflowy/startup/startup.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flutter_test/flutter_test.dart'; import 'package:flutter_test/flutter_test.dart';
import 'package:integration_test/integration_test.dart'; import 'package:integration_test/integration_test.dart';
import 'util/mock/mock_openai_repository.dart'; import 'util/mock/mock_openai_repository.dart';
import 'util/util.dart'; import 'util/util.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:appflowy_editor/src/render/toolbar/toolbar_widget.dart';
import 'package:appflowy/startup/startup.dart';
void main() { void main() {
IntegrationTestWidgetsFlutterBinding.ensureInitialized(); IntegrationTestWidgetsFlutterBinding.ensureInitialized();

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

After

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

After

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 11 KiB

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.0 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

After

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.6 KiB

View File

@ -1 +1,80 @@
{"images":[{"size":"60x60","expected-size":"180","filename":"180.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"40x40","expected-size":"80","filename":"80.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"40x40","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"60x60","expected-size":"120","filename":"120.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"57x57","expected-size":"57","filename":"57.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"58","filename":"58.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"29x29","expected-size":"29","filename":"29.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"1x"},{"size":"29x29","expected-size":"87","filename":"87.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"57x57","expected-size":"114","filename":"114.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"40","filename":"40.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"2x"},{"size":"20x20","expected-size":"60","filename":"60.png","folder":"Assets.xcassets/AppIcon.appiconset/","idiom":"iphone","scale":"3x"},{"size":"1024x1024","filename":"1024.png","expected-size":"1024","idiom":"ios-marketing","folder":"Assets.xcassets/AppIcon.appiconset/","scale":"1x"}]} {
"images" : [
{
"filename" : "40.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "20x20"
},
{
"filename" : "60.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "20x20"
},
{
"filename" : "29.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "29x29"
},
{
"filename" : "58.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "29x29"
},
{
"filename" : "87.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "29x29"
},
{
"filename" : "80.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "40x40"
},
{
"filename" : "120.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "40x40"
},
{
"filename" : "57.png",
"idiom" : "iphone",
"scale" : "1x",
"size" : "57x57"
},
{
"filename" : "114.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "57x57"
},
{
"filename" : "120.png",
"idiom" : "iphone",
"scale" : "2x",
"size" : "60x60"
},
{
"filename" : "180.png",
"idiom" : "iphone",
"scale" : "3x",
"size" : "60x60"
},
{
"filename" : "1024.png",
"idiom" : "ios-marketing",
"scale" : "1x",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -0,0 +1,6 @@
{
"info" : {
"author" : "xcode",
"version" : 1
}
}

View File

@ -150,7 +150,6 @@ class _MobileViewPageState extends State<MobileViewPage> {
onTap: (context) { onTap: (context) {
showMobileBottomSheet( showMobileBottomSheet(
context, context,
showDragHandle: true,
builder: (_) => _buildViewPageBottomSheet(context), builder: (_) => _buildViewPageBottomSheet(context),
); );
}, },

View File

@ -50,6 +50,8 @@ class _MobileBottomSheetRenameWidgetState
height: 42.0, height: 42.0,
child: FlowyTextField( child: FlowyTextField(
controller: controller, controller: controller,
textInputAction: TextInputAction.done,
onSubmitted: (text) => widget.onRename(text),
), ),
), ),
), ),

View File

@ -52,7 +52,6 @@ enum MobilePaneActionType {
final favoriteBloc = context.read<FavoriteBloc>(); final favoriteBloc = context.read<FavoriteBloc>();
showMobileBottomSheet( showMobileBottomSheet(
context, context,
showDragHandle: true,
builder: (context) { builder: (context) {
return MultiBlocProvider( return MultiBlocProvider(
providers: [ providers: [

View File

@ -6,7 +6,7 @@ import 'package:appflowy/plugins/database_view/widgets/card/card_cell_builder.da
import 'package:appflowy/plugins/database_view/widgets/card/cells/card_cell.dart'; import 'package:appflowy/plugins/database_view/widgets/card/cells/card_cell.dart';
import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell_bloc.dart'; import 'package:appflowy/plugins/database_view/widgets/row/cells/text_cell/text_cell_bloc.dart';
import 'package:easy_localization/easy_localization.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/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
@ -79,13 +79,9 @@ class MobileCardContent<CustomCardData> extends StatelessWidget {
final text = cardDataIsEmpty final text = cardDataIsEmpty
? LocaleKeys.grid_row_titlePlaceholder.tr() ? LocaleKeys.grid_row_titlePlaceholder.tr()
: cellData; : cellData;
final color = cardDataIsEmpty
final textStyle = Theme.of(context).textTheme.bodyMedium?.copyWith( ? Theme.of(context).hintColor
color: cardDataIsEmpty : Theme.of(context).colorScheme.onBackground;
? Theme.of(context).hintColor
: Theme.of(context).colorScheme.onBackground,
fontSize: 20,
);
return Row( return Row(
children: [ children: [
@ -94,9 +90,9 @@ class MobileCardContent<CustomCardData> extends StatelessWidget {
const HSpace(4), const HSpace(4),
], ],
Expanded( Expanded(
child: Text( child: FlowyText.regular(
text, text,
style: textStyle, color: color,
overflow: TextOverflow.ellipsis, overflow: TextOverflow.ellipsis,
), ),
), ),

View File

@ -16,7 +16,7 @@ const _supportedFieldTypes = [
FieldType.MultiSelect, FieldType.MultiSelect,
FieldType.DateTime, FieldType.DateTime,
FieldType.Checkbox, FieldType.Checkbox,
FieldType.Checklist, // FieldType.Checklist,
]; ];
class FieldOptions extends StatelessWidget { class FieldOptions extends StatelessWidget {

View File

@ -531,7 +531,7 @@ class _TimeOptionState extends State<_TimeOption> {
return FlowyOptionTile.checkbox( return FlowyOptionTile.checkbox(
text: format.title(), text: format.title(),
isSelected: selectedFormat == format, isSelected: selectedFormat == format,
showTopBorder: false, showTopBorder: index == 0,
onTap: () { onTap: () {
widget.onSelected(format); widget.onSelected(format);
setState(() { setState(() {

View File

@ -1,5 +1,6 @@
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/widgets/widgets.dart'; import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
import 'package:appflowy/plugins/base/drag_handler.dart'; import 'package:appflowy/plugins/base/drag_handler.dart';
import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart'; import 'package:appflowy/plugins/database_view/application/cell/cell_controller_builder.dart';
@ -12,6 +13,7 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:dartz/dartz.dart' hide State; import 'package:dartz/dartz.dart' hide State;
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
@ -73,15 +75,17 @@ class _MobileDateCellEditScreenState extends State<MobileDateCellEditScreen> {
initialChildSize: 0.6, initialChildSize: 0.6,
minChildSize: 0.6, minChildSize: 0.6,
builder: (_, controller) => Material( builder: (_, controller) => Material(
child: SingleChildScrollView( child: ColoredBox(
controller: controller, color: Theme.of(context).colorScheme.surface,
child: Column( child: SingleChildScrollView(
children: [ controller: controller,
const DragHandler(), child: Column(
_buildHeader(), children: [
const Divider(), const DragHandler(),
_buildBody(), _buildHeader(),
], _buildBody(),
],
),
), ),
), ),
), ),
@ -171,16 +175,16 @@ class _DateCellEditBody extends StatelessWidget {
children: [ children: [
FlowyOptionDecorateBox( FlowyOptionDecorateBox(
showTopBorder: false, showTopBorder: false,
child: _IncludeTimePicker(),
),
_ColoredDivider(),
FlowyOptionDecorateBox(
child: MobileDatePicker(), child: MobileDatePicker(),
), ),
_ColoredDivider(), _ColoredDivider(),
_EndDateSwitch(), _EndDateSwitch(),
_IncludeTimeSwitch(), _IncludeTimeSwitch(),
_StartDayTime(),
_EndDayTime(),
_ColoredDivider(), _ColoredDivider(),
_DateFormatOption(),
_TimeFormatOption(),
_ClearDateButton(), _ClearDateButton(),
_ColoredDivider(), _ColoredDivider(),
], ],
@ -201,6 +205,157 @@ class _ColoredDivider extends StatelessWidget {
} }
} }
class _IncludeTimePicker extends StatefulWidget {
const _IncludeTimePicker();
@override
State<_IncludeTimePicker> createState() => _IncludeTimePickerState();
}
class _IncludeTimePickerState extends State<_IncludeTimePicker> {
String? _selectedTime;
@override
Widget build(BuildContext context) {
return BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
builder: (context, state) {
final startDay = state.dateStr;
final endDay = state.endDateStr;
final includeTime = state.includeTime;
final use24hFormat =
state.dateTypeOptionPB.timeFormat == TimeFormatPB.TwentyFourHour;
if (startDay == null || startDay.isEmpty) {
return const Divider(
height: 1,
);
}
return Container(
margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
_buildTime(
context,
includeTime,
use24hFormat,
true,
startDay,
state.timeStr,
),
VSpace(
8.0,
color: Theme.of(context).colorScheme.surface,
),
_buildTime(
context,
includeTime,
use24hFormat,
false,
endDay,
state.endTimeStr,
),
],
),
);
},
);
}
Widget _buildTime(
BuildContext context,
bool isIncludeTime,
bool use24hFormat,
bool isStartDay,
String? dateStr,
String? timeStr,
) {
if (dateStr == null) {
return const SizedBox.shrink();
}
final List<Widget> children = [];
if (!isIncludeTime) {
children.addAll([
const HSpace(12.0),
FlowyText(
dateStr,
),
]);
} else {
children.addAll([
Expanded(
child: FlowyText(
dateStr,
textAlign: TextAlign.center,
),
),
Container(
width: 1,
height: 16,
color: Colors.grey,
),
Expanded(
child: FlowyText(
timeStr ?? '',
textAlign: TextAlign.center,
),
),
]);
}
return GestureDetector(
onTap: () async {
final bloc = context.read<DateCellCalendarBloc>();
await showMobileBottomSheet(
context,
builder: (context) {
return ConstrainedBox(
constraints: const BoxConstraints(
maxHeight: 300,
),
child: CupertinoDatePicker(
showDayOfWeek: false,
mode: CupertinoDatePickerMode.time,
use24hFormat: use24hFormat,
onDateTimeChanged: (dateTime) {
_selectedTime = use24hFormat
? DateFormat('HH:mm').format(dateTime)
: DateFormat('hh:mm a').format(dateTime);
},
),
);
},
);
if (_selectedTime != null) {
bloc.add(
isStartDay
? DateCellCalendarEvent.setTime(_selectedTime!)
: DateCellCalendarEvent.setEndTime(_selectedTime!),
);
}
},
child: Container(
constraints: const BoxConstraints(
minHeight: 36,
),
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Theme.of(context).colorScheme.secondaryContainer,
border: Border.all(
color: Theme.of(context).colorScheme.outline,
width: 1,
),
),
child: Row(
children: children,
),
),
);
}
}
class _EndDateSwitch extends StatelessWidget { class _EndDateSwitch extends StatelessWidget {
const _EndDateSwitch(); const _EndDateSwitch();
@ -211,7 +366,6 @@ class _EndDateSwitch extends StatelessWidget {
builder: (context, isRange) { builder: (context, isRange) {
return FlowyOptionTile.switcher( return FlowyOptionTile.switcher(
text: LocaleKeys.grid_field_isRange.tr(), text: LocaleKeys.grid_field_isRange.tr(),
leftIcon: const FlowySvg(FlowySvgs.date_s),
isSelected: isRange, isSelected: isRange,
onValueChanged: (value) { onValueChanged: (value) {
context context
@ -235,7 +389,6 @@ class _IncludeTimeSwitch extends StatelessWidget {
return FlowyOptionTile.switcher( return FlowyOptionTile.switcher(
showTopBorder: false, showTopBorder: false,
text: LocaleKeys.grid_field_includeTime.tr(), text: LocaleKeys.grid_field_includeTime.tr(),
leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s),
isSelected: includeTime, isSelected: includeTime,
onValueChanged: (value) { onValueChanged: (value) {
context context
@ -248,76 +401,6 @@ class _IncludeTimeSwitch extends StatelessWidget {
} }
} }
class _StartDayTime extends StatelessWidget {
const _StartDayTime();
@override
Widget build(BuildContext context) {
return BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
builder: (context, state) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: state.includeTime
? Row(
children: [
Text(
state.isRange
? LocaleKeys.grid_field_startDateTime.tr()
: LocaleKeys.grid_field_dateTime.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
// TODO(yijing): improve width
SizedBox(
width: 180,
child: _TimeTextField(
timeStr: state.timeStr,
isEndTime: false,
),
),
],
)
: const SizedBox.shrink(),
);
},
);
}
}
class _EndDayTime extends StatelessWidget {
const _EndDayTime();
@override
Widget build(BuildContext context) {
return BlocBuilder<DateCellCalendarBloc, DateCellCalendarState>(
builder: (context, state) {
return AnimatedSwitcher(
duration: const Duration(milliseconds: 300),
child: state.includeTime && state.endTimeStr != null
? Row(
children: [
Text(
LocaleKeys.grid_field_endDateTime.tr(),
style: Theme.of(context).textTheme.titleMedium,
),
const Spacer(),
// TODO(yijing): improve width
SizedBox(
width: 180,
child: _TimeTextField(
timeStr: state.timeStr,
isEndTime: true,
),
),
],
)
: const SizedBox.shrink(),
);
},
);
}
}
class _TimeTextField extends StatefulWidget { class _TimeTextField extends StatefulWidget {
const _TimeTextField({ const _TimeTextField({
required this.timeStr, required this.timeStr,
@ -378,7 +461,6 @@ class _ClearDateButton extends StatelessWidget {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyOptionTile.text( return FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.grid_field_clearDate.tr(), text: LocaleKeys.grid_field_clearDate.tr(),
onTap: () => context onTap: () => context
.read<DateCellCalendarBloc>() .read<DateCellCalendarBloc>()
@ -386,68 +468,3 @@ class _ClearDateButton extends StatelessWidget {
); );
} }
} }
class _TimeFormatOption extends StatelessWidget {
const _TimeFormatOption();
@override
Widget build(BuildContext context) {
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState,
TimeFormatPB>(
selector: (state) => state.dateTypeOptionPB.timeFormat,
builder: (context, state) {
return FlowyOptionTile.text(
showTopBorder: false,
text: LocaleKeys.settings_appearance_timeFormat_label.tr(),
leftIcon: const FlowySvg(FlowySvgs.time_s),
);
// TimeFormatListTile(
// currentFormatStr: state.title(),
// groupValue: context
// .watch<DateCellCalendarBloc>()
// .state
// .dateTypeOptionPB
// .timeFormat,
// onChanged: (newFormat) {
// if (newFormat == null) return;
// context
// .read<DateCellCalendarBloc>()
// .add(DateCellCalendarEvent.setTimeFormat(newFormat));
// },
// );
},
);
}
}
class _DateFormatOption extends StatelessWidget {
const _DateFormatOption();
@override
Widget build(BuildContext context) {
return BlocSelector<DateCellCalendarBloc, DateCellCalendarState,
DateFormatPB>(
selector: (state) => state.dateTypeOptionPB.dateFormat,
builder: (context, state) {
return FlowyOptionTile.text(
text: LocaleKeys.settings_appearance_dateFormat_label.tr(),
leftIcon: const FlowySvg(FlowySvgs.clock_alarm_s),
);
// DateFormatListTile(
// currentFormatStr: state.title(),
// groupValue: context
// .watch<DateCellCalendarBloc>()
// .state
// .dateTypeOptionPB
// .dateFormat,
// onChanged: (newFormat) {
// if (newFormat == null) return;
// context
// .read<DateCellCalendarBloc>()
// .add(DateCellCalendarEvent.setDateFormat(newFormat));
// },
// );
},
);
}
}

View File

@ -143,7 +143,9 @@ class _MobileRecentViewState extends State<MobileRecentView> {
builder: ((context, snapshot) { builder: ((context, snapshot) {
final node = snapshot.data; final node = snapshot.data;
final placeholder = Container( final placeholder = Container(
color: Theme.of(context).colorScheme.onSecondaryContainer, // random color, update it once we have a better placeholder
color:
Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.2),
); );
if (node == null) { if (node == null) {
return placeholder; return placeholder;

View File

@ -141,7 +141,7 @@ class _RemoveIconButton extends StatelessWidget {
child: FlowyButton( child: FlowyButton(
onTap: onTap, onTap: onTap,
useIntrinsicWidth: true, useIntrinsicWidth: true,
text: FlowyText( text: FlowyText.small(
LocaleKeys.document_plugins_cover_removeIcon.tr(), LocaleKeys.document_plugins_cover_removeIcon.tr(),
), ),
leftIcon: const FlowySvg(FlowySvgs.delete_s), leftIcon: const FlowySvg(FlowySvgs.delete_s),

View File

@ -80,6 +80,7 @@ class DateCellCalendarBloc
await _updateDateData(isRange: isRange); await _updateDateData(isRange: isRange);
}, },
setTime: (timeStr) async { setTime: (timeStr) async {
emit(state.copyWith(timeStr: timeStr));
await _updateDateData(timeStr: timeStr); await _updateDateData(timeStr: timeStr);
}, },
selectDateRange: (DateTime? start, DateTime? end) async { selectDateRange: (DateTime? start, DateTime? end) async {
@ -158,6 +159,7 @@ class DateCellCalendarBloc
} }
}, },
setEndTime: (String endTime) async { setEndTime: (String endTime) async {
emit(state.copyWith(endTimeStr: endTime));
await _updateDateData(endTimeStr: endTime); await _updateDateData(endTimeStr: endTime);
}, },
setDateFormat: (dateFormat) async { setDateFormat: (dateFormat) async {

View File

@ -91,11 +91,14 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
final List<ToolbarItem> toolbarItems = [ final List<ToolbarItem> toolbarItems = [
smartEditItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable, smartEditItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,
paragraphItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable, paragraphItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,
...(headingItems ...headingItems
..forEach( ..forEach(
(e) => e.isActive = onlyShowInSingleSelectionAndTextType, (e) => e.isActive = onlyShowInSingleSelectionAndTextType,
)), ),
...markdownFormatItems, ...markdownFormatItems
..forEach(
(e) => e.isActive = showInAnyTextType,
),
quoteItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable, quoteItem..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,
bulletedListItem bulletedListItem
..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable, ..isActive = onlyShowInSingleTextTypeSelectionAndExcludeTable,
@ -497,3 +500,14 @@ class _AppFlowyEditorPageState extends State<AppFlowyEditorPage> {
await editorState.apply(transaction); await editorState.apply(transaction);
} }
} }
bool showInAnyTextType(EditorState editorState) {
final selection = editorState.selection;
if (selection == null) {
return false;
}
final nodes = editorState.getNodesInSelection(selection);
return nodes.any(
(node) => toolbarItemWhiteList.contains(node.type),
);
}

View File

@ -70,7 +70,6 @@ class MobileBlockActionButtons extends StatelessWidget {
showMobileBottomSheet( showMobileBottomSheet(
context, context,
showHeader: true, showHeader: true,
showDragHandle: true,
showCloseButton: true, showCloseButton: true,
title: LocaleKeys.document_plugins_action.tr(), title: LocaleKeys.document_plugins_action.tr(),
builder: (context) { builder: (context) {

View File

@ -34,16 +34,24 @@ final alignToolbarItem = ToolbarItem(
data = FlowySvgs.toolbar_align_right_s; data = FlowySvgs.toolbar_align_right_s;
} }
final child = MouseRegion( // final child = MouseRegion(
cursor: SystemMouseCursors.click, // cursor: SystemMouseCursors.click,
child: FlowyTooltip( // child: FlowyTooltip(
message: LocaleKeys.document_plugins_optionAction_align.tr(), // message: LocaleKeys.document_plugins_optionAction_align.tr(),
child: FlowySvg( // child: FlowySvg(
data, // data,
size: const Size.square(16), // size: const Size.square(16),
color: isHighlight ? highlightColor : Colors.white, // color: isHighlight ? highlightColor : Colors.white,
), // ),
), // ),
// );
// the above code will cause an error in Flutter 3.13:
// Cannot hit test a render box that has never been laid out.
final child = FlowySvg(
data,
size: const Size.square(16),
color: isHighlight ? highlightColor : Colors.white,
); );
return Padding( return Padding(

View File

@ -230,9 +230,11 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
alignment: Alignment.bottomLeft, alignment: Alignment.bottomLeft,
width: double.infinity, width: double.infinity,
padding: PlatformExtension.isDesktopOrWeb padding: PlatformExtension.isDesktopOrWeb
? EditorStyleCustomizer.documentPadding ? EdgeInsets.symmetric(
horizontal: EditorStyleCustomizer.documentPadding.right,
)
: EdgeInsets.symmetric( : EdgeInsets.symmetric(
horizontal: EditorStyleCustomizer.documentPadding.left - 6.0, horizontal: EditorStyleCustomizer.documentPadding.left,
), ),
child: SizedBox( child: SizedBox(
height: 28, height: 28,
@ -276,7 +278,7 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
), ),
useIntrinsicWidth: true, useIntrinsicWidth: true,
leftIcon: const FlowySvg(FlowySvgs.image_s), leftIcon: const FlowySvg(FlowySvgs.image_s),
text: FlowyText.regular( text: FlowyText.small(
LocaleKeys.document_plugins_cover_addCover.tr(), LocaleKeys.document_plugins_cover_addCover.tr(),
), ),
), ),
@ -293,7 +295,7 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
Icons.emoji_emotions_outlined, Icons.emoji_emotions_outlined,
size: 18, size: 18,
), ),
text: FlowyText.regular( text: FlowyText.small(
LocaleKeys.document_plugins_cover_removeIcon.tr(), LocaleKeys.document_plugins_cover_removeIcon.tr(),
), ),
), ),
@ -306,7 +308,7 @@ class _DocumentHeaderToolbarState extends State<DocumentHeaderToolbar> {
Icons.emoji_emotions_outlined, Icons.emoji_emotions_outlined,
size: 18, size: 18,
), ),
text: FlowyText.regular( text: FlowyText.small(
LocaleKeys.document_plugins_cover_addIcon.tr(), LocaleKeys.document_plugins_cover_addIcon.tr(),
), ),
onTap: PlatformExtension.isDesktop onTap: PlatformExtension.isDesktop
@ -468,7 +470,10 @@ class DocumentCoverState extends State<DocumentCover> {
}, },
); );
}, },
fillColor: Theme.of(context).colorScheme.onSurfaceVariant, fillColor: Theme.of(context)
.colorScheme
.onSurfaceVariant
.withOpacity(0.5),
height: 32, height: 32,
title: LocaleKeys.document_plugins_cover_changeCover.tr(), title: LocaleKeys.document_plugins_cover_changeCover.tr(),
), ),
@ -587,7 +592,7 @@ class DeleteCoverButton extends StatelessWidget {
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fillColor = PlatformExtension.isDesktopOrWeb final fillColor = PlatformExtension.isDesktopOrWeb
? Theme.of(context).colorScheme.surface.withOpacity(0.5) ? Theme.of(context).colorScheme.surface.withOpacity(0.5)
: Theme.of(context).colorScheme.onSurfaceVariant; : Theme.of(context).colorScheme.onSurfaceVariant.withOpacity(0.5);
final svgColor = PlatformExtension.isDesktopOrWeb final svgColor = PlatformExtension.isDesktopOrWeb
? Theme.of(context).colorScheme.tertiary ? Theme.of(context).colorScheme.tertiary
: Theme.of(context).colorScheme.onPrimary; : Theme.of(context).colorScheme.onPrimary;

View File

@ -42,11 +42,13 @@ class MentionBlock extends StatelessWidget {
required this.mention, required this.mention,
required this.node, required this.node,
required this.index, required this.index,
required this.textStyle,
}); });
final Map<String, dynamic> mention; final Map<String, dynamic> mention;
final Node node; final Node node;
final int index; final int index;
final TextStyle? textStyle;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -58,6 +60,7 @@ class MentionBlock extends StatelessWidget {
return MentionPageBlock( return MentionPageBlock(
key: ValueKey(pageId), key: ValueKey(pageId),
pageId: pageId, pageId: pageId,
textStyle: textStyle,
); );
case MentionType.reminder: case MentionType.reminder:
case MentionType.date: case MentionType.date:

View File

@ -1,5 +1,4 @@
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/document/presentation/more/cubit/document_appearance_cubit.dart';
import 'package:appflowy/plugins/trash/application/trash_service.dart'; import 'package:appflowy/plugins/trash/application/trash_service.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart'; import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
@ -22,9 +21,11 @@ class MentionPageBlock extends StatefulWidget {
const MentionPageBlock({ const MentionPageBlock({
super.key, super.key,
required this.pageId, required this.pageId,
required this.textStyle,
}); });
final String pageId; final String pageId;
final TextStyle? textStyle;
@override @override
State<MentionPageBlock> createState() => _MentionPageBlockState(); State<MentionPageBlock> createState() => _MentionPageBlockState();
@ -59,7 +60,6 @@ class _MentionPageBlockState extends State<MentionPageBlock> {
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final fontSize = context.read<DocumentAppearanceCubit>().state.fontSize;
return FutureBuilder<ViewPB?>( return FutureBuilder<ViewPB?>(
initialData: pageMemorizer[widget.pageId], initialData: pageMemorizer[widget.pageId],
future: viewPBFuture, future: viewPBFuture,
@ -71,6 +71,7 @@ class _MentionPageBlockState extends State<MentionPageBlock> {
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
updateSelection(); updateSelection();
final iconSize = widget.textStyle?.fontSize ?? 16.0;
return Padding( return Padding(
padding: const EdgeInsets.symmetric(horizontal: 2), padding: const EdgeInsets.symmetric(horizontal: 2),
child: FlowyHover( child: FlowyHover(
@ -84,13 +85,14 @@ class _MentionPageBlockState extends State<MentionPageBlock> {
const HSpace(4), const HSpace(4),
FlowySvg( FlowySvg(
view.layout.icon, view.layout.icon,
size: const Size.square(18.0), size: Size.square(iconSize + 2.0),
), ),
const HSpace(2), const HSpace(2),
FlowyText( FlowyText(
view.name, view.name,
decoration: TextDecoration.underline, decoration: TextDecoration.underline,
fontSize: fontSize, fontSize: widget.textStyle?.fontSize,
fontWeight: widget.textStyle?.fontWeight,
), ),
const HSpace(2), const HSpace(2),
], ],

View File

@ -52,7 +52,6 @@ Future<void> _showBlockActionSheet(
builder: (context) { builder: (context) {
return BlockActionBottomSheet( return BlockActionBottomSheet(
extendActionWidgets: [ extendActionWidgets: [
const VSpace(8),
Row( Row(
children: [ children: [
Expanded( Expanded(

View File

@ -140,9 +140,10 @@ class EditorStyleCustomizer {
fontSize + 2, fontSize + 2,
fontSize, fontSize,
]; ];
return TextStyle( final fontFamily = context.read<DocumentAppearanceCubit>().state.fontFamily;
return baseTextStyle(fontFamily, fontWeight: FontWeight.bold).copyWith(
fontWeight: FontWeight.w600,
fontSize: fontSizes.elementAtOrNull(level - 1) ?? fontSize, fontSize: fontSizes.elementAtOrNull(level - 1) ?? fontSize,
fontWeight: FontWeight.bold,
); );
} }
@ -217,11 +218,12 @@ class EditorStyleCustomizer {
Node node, Node node,
int index, int index,
TextInsert text, TextInsert text,
TextSpan textSpan, TextSpan before,
TextSpan after,
) { ) {
final attributes = text.attributes; final attributes = text.attributes;
if (attributes == null) { if (attributes == null) {
return textSpan; return before;
} }
// try to refresh font here. // try to refresh font here.
@ -240,6 +242,7 @@ class EditorStyleCustomizer {
final type = mention[MentionBlockKeys.type]; final type = mention[MentionBlockKeys.type];
return WidgetSpan( return WidgetSpan(
alignment: PlaceholderAlignment.middle, alignment: PlaceholderAlignment.middle,
style: after.style,
child: MentionBlock( child: MentionBlock(
key: ValueKey( key: ValueKey(
switch (type) { switch (type) {
@ -253,6 +256,7 @@ class EditorStyleCustomizer {
node: node, node: node,
index: index, index: index,
mention: mention, mention: mention,
textStyle: after.style,
), ),
); );
} }
@ -275,7 +279,7 @@ class EditorStyleCustomizer {
final href = attributes[AppFlowyRichTextKeys.href] as String?; final href = attributes[AppFlowyRichTextKeys.href] as String?;
if (PlatformExtension.isMobile && href != null) { if (PlatformExtension.isMobile && href != null) {
return TextSpan( return TextSpan(
style: textSpan.style, style: before.style,
text: text.text, text: text.text,
recognizer: TapGestureRecognizer() recognizer: TapGestureRecognizer()
..onTap = () { ..onTap = () {
@ -305,7 +309,8 @@ class EditorStyleCustomizer {
node, node,
index, index,
text, text,
textSpan, before,
after,
); );
} }

View File

@ -60,13 +60,14 @@ void showSnackBarMessage(
? null ? null
: SnackBarAction( : SnackBarAction(
label: LocaleKeys.button_cancel.tr(), label: LocaleKeys.button_cancel.tr(),
textColor: Theme.of(context).colorScheme.onSurface, textColor: Colors.white,
onPressed: () { onPressed: () {
ScaffoldMessenger.of(context).hideCurrentSnackBar(); ScaffoldMessenger.of(context).hideCurrentSnackBar();
}, },
), ),
content: FlowyText( content: FlowyText(
message, message,
color: Colors.white,
), ),
), ),
); );

View File

@ -152,6 +152,7 @@ class _ViewTitleState extends State<_ViewTitle> {
String name = ''; String name = '';
String icon = ''; String icon = '';
String inputtingName = '';
@override @override
void initState() { void initState() {
@ -266,6 +267,18 @@ class _ViewTitleState extends State<_ViewTitle> {
} }
popoverController.close(); popoverController.close();
}, },
onChanged: (text) async {
inputtingName = text;
},
onCanceled: () async {
if (inputtingName.isNotEmpty && inputtingName != name) {
await ViewBackendService.updateView(
viewId: widget.view.id,
name: inputtingName,
);
popoverController.close();
}
},
), ),
), ),
const HSpace(4.0), const HSpace(4.0),
@ -280,6 +293,7 @@ class _ViewTitleState extends State<_ViewTitle> {
} }
void _resetTextEditingController() { void _resetTextEditingController() {
inputtingName = name;
textEditingController textEditingController
..text = name ..text = name
..selection = TextSelection( ..selection = TextSelection(

View File

@ -1,3 +1,5 @@
import 'dart:io';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class FlowyText extends StatelessWidget { class FlowyText extends StatelessWidget {
@ -28,6 +30,21 @@ class FlowyText extends StatelessWidget {
Key? key, Key? key,
}) : super(key: key); }) : super(key: key);
FlowyText.small(
this.text, {
this.overflow,
this.color,
this.textAlign,
this.maxLines = 1,
this.decoration,
this.selectable = false,
this.fontFamily,
this.fallbackFontFamily,
Key? key,
}) : fontWeight = FontWeight.w400,
fontSize = (Platform.isIOS || Platform.isAndroid) ? 14 : 12,
super(key: key);
const FlowyText.regular( const FlowyText.regular(
this.text, { this.text, {
this.fontSize, this.fontSize,

View File

@ -54,8 +54,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "9c7a4e" ref: "4995d21"
resolved-ref: "9c7a4ee671768524b0dd6f3ebb12dd845932ee74" resolved-ref: "4995d21ff49907c71286e668f938f830bf94ca0d"
url: "https://github.com/AppFlowy-IO/appflowy-editor.git" url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git source: git
version: "2.0.0" version: "2.0.0"
@ -580,8 +580,8 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "140b530" ref: "4a5cac"
resolved-ref: "140b53091ce7ad971e97c1d5a53fe0875596326d" resolved-ref: "4a5cac57e31c0ffd49cd6257a9e078f084ae342c"
url: "https://github.com/LucasXu0/emoji_mart.git" url: "https://github.com/LucasXu0/emoji_mart.git"
source: git source: git
version: "1.0.2" version: "1.0.2"

View File

@ -46,7 +46,7 @@ dependencies:
appflowy_editor: appflowy_editor:
git: git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "9c7a4e" ref: "4995d21"
appflowy_popover: appflowy_popover:
path: packages/appflowy_popover path: packages/appflowy_popover
@ -115,7 +115,7 @@ dependencies:
flutter_emoji_mart: flutter_emoji_mart:
git: git:
url: https://github.com/LucasXu0/emoji_mart.git url: https://github.com/LucasXu0/emoji_mart.git
ref: "140b530" ref: "4a5cac"
# Notifications # Notifications
# TODO: Consider implementing custom package # TODO: Consider implementing custom package