mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
Merge branch 'main' into workspace-invite
This commit is contained in:
commit
0aa4aa956d
2
frontend/.vscode/tasks.json
vendored
2
frontend/.vscode/tasks.json
vendored
@ -257,7 +257,7 @@
|
|||||||
"label": "AF: Tauri UI Dev",
|
"label": "AF: Tauri UI Dev",
|
||||||
"type": "shell",
|
"type": "shell",
|
||||||
"isBackground": true,
|
"isBackground": true,
|
||||||
"command": "pnpm run tauri:dev",
|
"command": "pnpm run sync:i18n && pnpm run dev",
|
||||||
"options": {
|
"options": {
|
||||||
"cwd": "${workspaceFolder}/appflowy_tauri"
|
"cwd": "${workspaceFolder}/appflowy_tauri"
|
||||||
}
|
}
|
||||||
|
@ -148,7 +148,7 @@ class _MobileViewPageState extends State<MobileViewPage> {
|
|||||||
context,
|
context,
|
||||||
showDragHandle: true,
|
showDragHandle: true,
|
||||||
showDivider: false,
|
showDivider: false,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
builder: (_) => _buildViewPageBottomSheet(context),
|
builder: (_) => _buildViewPageBottomSheet(context),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -2,7 +2,6 @@ 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/widgets/flowy_mobile_quick_action_button.dart';
|
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
|
||||||
import 'package:easy_localization/easy_localization.dart';
|
import 'package:easy_localization/easy_localization.dart';
|
||||||
import 'package:flowy_infra_ui/widget/separated_flex.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
enum MobileViewItemBottomSheetBodyAction {
|
enum MobileViewItemBottomSheetBodyAction {
|
||||||
@ -26,12 +25,8 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SeparatedColumn(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
separatorBuilder: () => const Divider(
|
|
||||||
height: 8.5,
|
|
||||||
thickness: 0.5,
|
|
||||||
),
|
|
||||||
children: [
|
children: [
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_rename.tr(),
|
text: LocaleKeys.button_rename.tr(),
|
||||||
@ -40,6 +35,7 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewItemBottomSheetBodyAction.rename,
|
MobileViewItemBottomSheetBodyAction.rename,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: isFavorite
|
text: isFavorite
|
||||||
? LocaleKeys.button_removeFromFavorites.tr()
|
? LocaleKeys.button_removeFromFavorites.tr()
|
||||||
@ -54,6 +50,7 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
|
|||||||
: MobileViewItemBottomSheetBodyAction.addToFavorites,
|
: MobileViewItemBottomSheetBodyAction.addToFavorites,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_duplicate.tr(),
|
text: LocaleKeys.button_duplicate.tr(),
|
||||||
icon: FlowySvgs.m_duplicate_s,
|
icon: FlowySvgs.m_duplicate_s,
|
||||||
@ -61,6 +58,7 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewItemBottomSheetBodyAction.duplicate,
|
MobileViewItemBottomSheetBodyAction.duplicate,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_delete.tr(),
|
text: LocaleKeys.button_delete.tr(),
|
||||||
textColor: Theme.of(context).colorScheme.error,
|
textColor: Theme.of(context).colorScheme.error,
|
||||||
@ -70,7 +68,13 @@ class MobileViewItemBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewItemBottomSheetBodyAction.delete,
|
MobileViewItemBottomSheetBodyAction.delete,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _divider() => const Divider(
|
||||||
|
height: 8.5,
|
||||||
|
thickness: 0.5,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,6 @@ import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
|
|||||||
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
|
import 'package:appflowy/mobile/presentation/widgets/flowy_mobile_quick_action_button.dart';
|
||||||
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
|
||||||
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:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
enum MobileViewBottomSheetBodyAction {
|
enum MobileViewBottomSheetBodyAction {
|
||||||
@ -85,12 +84,8 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final isFavorite = view.isFavorite;
|
final isFavorite = view.isFavorite;
|
||||||
return SeparatedColumn(
|
return Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.stretch,
|
crossAxisAlignment: CrossAxisAlignment.stretch,
|
||||||
separatorBuilder: () => const Divider(
|
|
||||||
height: 8.5,
|
|
||||||
thickness: 0.5,
|
|
||||||
),
|
|
||||||
children: [
|
children: [
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_rename.tr(),
|
text: LocaleKeys.button_rename.tr(),
|
||||||
@ -99,6 +94,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewBottomSheetBodyAction.rename,
|
MobileViewBottomSheetBodyAction.rename,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: isFavorite
|
text: isFavorite
|
||||||
? LocaleKeys.button_removeFromFavorites.tr()
|
? LocaleKeys.button_removeFromFavorites.tr()
|
||||||
@ -113,6 +109,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
|||||||
: MobileViewBottomSheetBodyAction.addToFavorites,
|
: MobileViewBottomSheetBodyAction.addToFavorites,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_duplicate.tr(),
|
text: LocaleKeys.button_duplicate.tr(),
|
||||||
icon: FlowySvgs.m_duplicate_s,
|
icon: FlowySvgs.m_duplicate_s,
|
||||||
@ -120,6 +117,7 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewBottomSheetBodyAction.duplicate,
|
MobileViewBottomSheetBodyAction.duplicate,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
MobileQuickActionButton(
|
MobileQuickActionButton(
|
||||||
text: LocaleKeys.button_delete.tr(),
|
text: LocaleKeys.button_delete.tr(),
|
||||||
textColor: Theme.of(context).colorScheme.error,
|
textColor: Theme.of(context).colorScheme.error,
|
||||||
@ -129,7 +127,13 @@ class MobileViewBottomSheetBody extends StatelessWidget {
|
|||||||
MobileViewBottomSheetBodyAction.delete,
|
MobileViewBottomSheetBodyAction.delete,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
_divider(),
|
||||||
],
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Widget _divider() => const Divider(
|
||||||
|
height: 8.5,
|
||||||
|
thickness: 0.5,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
@ -54,7 +54,7 @@ enum MobilePaneActionType {
|
|||||||
context,
|
context,
|
||||||
showDragHandle: true,
|
showDragHandle: true,
|
||||||
showDivider: false,
|
showDivider: false,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
useRootNavigator: true,
|
useRootNavigator: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
return MultiBlocProvider(
|
return MultiBlocProvider(
|
||||||
|
@ -150,6 +150,7 @@ class _MobileRowDetailPageState extends State<MobileRowDetailPage> {
|
|||||||
icon: FlowySvgs.m_delete_m,
|
icon: FlowySvgs.m_delete_m,
|
||||||
iconColor: Theme.of(context).colorScheme.error,
|
iconColor: Theme.of(context).colorScheme.error,
|
||||||
),
|
),
|
||||||
|
const Divider(height: 8.5, thickness: 0.5),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
@ -40,7 +40,7 @@ Future<FieldType?> showFieldTypeGridBottomSheet(
|
|||||||
showCloseButton: true,
|
showCloseButton: true,
|
||||||
elevation: 20,
|
elevation: 20,
|
||||||
title: title,
|
title: title,
|
||||||
backgroundColor: Theme.of(context).colorScheme.surface,
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
enableDraggableScrollable: true,
|
enableDraggableScrollable: true,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final typeOptionMenuItemValue = mobileSupportedFieldTypes
|
final typeOptionMenuItemValue = mobileSupportedFieldTypes
|
||||||
@ -94,9 +94,6 @@ void mobileCreateFieldWorkflow(
|
|||||||
if (optionValues != null) {
|
if (optionValues != null) {
|
||||||
await optionValues.create(viewId: viewId, position: position);
|
await optionValues.create(viewId: viewId, position: position);
|
||||||
}
|
}
|
||||||
if (context.mounted) {
|
|
||||||
context.pop();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Used to edit a field.
|
/// Used to edit a field.
|
||||||
|
@ -262,11 +262,9 @@ class _SortItem extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
padding: const EdgeInsets.symmetric(horizontal: 12.0),
|
||||||
child: Expanded(
|
child: FlowyText.medium(
|
||||||
child: FlowyText.medium(
|
LocaleKeys.grid_sort_by.tr(),
|
||||||
LocaleKeys.grid_sort_by.tr(),
|
fontSize: 15,
|
||||||
fontSize: 15,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
const VSpace(10),
|
const VSpace(10),
|
||||||
@ -407,6 +405,8 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
|
|
||||||
final SortInfo? sortInfo;
|
final SortInfo? sortInfo;
|
||||||
|
|
||||||
|
bool get isCreatingNewSort => sortInfo == null;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Column(
|
return Column(
|
||||||
@ -417,7 +417,7 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
padding: const EdgeInsets.symmetric(horizontal: 16),
|
padding: const EdgeInsets.symmetric(horizontal: 16),
|
||||||
child: DefaultTabController(
|
child: DefaultTabController(
|
||||||
length: 2,
|
length: 2,
|
||||||
initialIndex: sortInfo == null
|
initialIndex: isCreatingNewSort
|
||||||
? 0
|
? 0
|
||||||
: sortInfo!.sortPB.condition == SortConditionPB.Ascending
|
: sortInfo!.sortPB.condition == SortConditionPB.Ascending
|
||||||
? 0
|
? 0
|
||||||
@ -489,30 +489,40 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
child: BlocBuilder<SortEditorBloc, SortEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
final fields = state.allFields
|
final fields = state.allFields
|
||||||
.where(
|
.where((field) => field.canCreateSort || field.hasSort)
|
||||||
(field) =>
|
|
||||||
field.canCreateSort ||
|
|
||||||
sortInfo != null && sortInfo!.fieldId == field.id,
|
|
||||||
)
|
|
||||||
.toList();
|
.toList();
|
||||||
return ListView.builder(
|
return ListView.builder(
|
||||||
itemCount: fields.length,
|
itemCount: fields.length,
|
||||||
itemBuilder: (context, index) {
|
itemBuilder: (context, index) {
|
||||||
final fieldInfo = fields[index];
|
final fieldInfo = fields[index];
|
||||||
final isSelected = sortInfo == null
|
final isSelected = isCreatingNewSort
|
||||||
? context
|
? context
|
||||||
.watch<MobileSortEditorCubit>()
|
.watch<MobileSortEditorCubit>()
|
||||||
.state
|
.state
|
||||||
.newSortFieldId ==
|
.newSortFieldId ==
|
||||||
fieldInfo.id
|
fieldInfo.id
|
||||||
: sortInfo!.fieldId == fieldInfo.id;
|
: sortInfo!.fieldId == fieldInfo.id;
|
||||||
|
|
||||||
|
final enabled = fieldInfo.canCreateSort ||
|
||||||
|
isCreatingNewSort && !fieldInfo.hasSort ||
|
||||||
|
!isCreatingNewSort && sortInfo!.fieldId == fieldInfo.id;
|
||||||
|
|
||||||
return FlowyOptionTile.checkbox(
|
return FlowyOptionTile.checkbox(
|
||||||
text: fieldInfo.field.name,
|
text: fieldInfo.field.name,
|
||||||
isSelected: isSelected,
|
isSelected: isSelected,
|
||||||
|
textColor: enabled ? null : Theme.of(context).disabledColor,
|
||||||
showTopBorder: false,
|
showTopBorder: false,
|
||||||
onTap: () {
|
onTap: () {
|
||||||
if (!isSelected) {
|
if (isSelected) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (enabled) {
|
||||||
_changeFieldId(context, fieldInfo.id);
|
_changeFieldId(context, fieldInfo.id);
|
||||||
|
} else {
|
||||||
|
Fluttertoast.showToast(
|
||||||
|
msg: LocaleKeys.grid_sort_fieldInUse.tr(),
|
||||||
|
gravity: ToastGravity.BOTTOM,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@ -526,7 +536,7 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _changeCondition(BuildContext context, SortConditionPB newCondition) {
|
void _changeCondition(BuildContext context, SortConditionPB newCondition) {
|
||||||
if (sortInfo == null) {
|
if (isCreatingNewSort) {
|
||||||
context.read<MobileSortEditorCubit>().changeSortCondition(newCondition);
|
context.read<MobileSortEditorCubit>().changeSortCondition(newCondition);
|
||||||
} else {
|
} else {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
@ -539,7 +549,7 @@ class _SortDetailContent extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void _changeFieldId(BuildContext context, String newFieldId) {
|
void _changeFieldId(BuildContext context, String newFieldId) {
|
||||||
if (sortInfo == null) {
|
if (isCreatingNewSort) {
|
||||||
context.read<MobileSortEditorCubit>().changeFieldId(newFieldId);
|
context.read<MobileSortEditorCubit>().changeFieldId(newFieldId);
|
||||||
} else {
|
} else {
|
||||||
context.read<SortEditorBloc>().add(
|
context.read<SortEditorBloc>().add(
|
||||||
|
@ -183,6 +183,7 @@ class MobileDatabaseViewListButton extends StatelessWidget {
|
|||||||
showMobileBottomSheet(
|
showMobileBottomSheet(
|
||||||
context,
|
context,
|
||||||
showDragHandle: true,
|
showDragHandle: true,
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return BlocProvider<ViewBloc>(
|
return BlocProvider<ViewBloc>(
|
||||||
create: (_) =>
|
create: (_) =>
|
||||||
|
@ -7,6 +7,7 @@ import 'package:appflowy/mobile/presentation/widgets/widgets.dart';
|
|||||||
import 'package:appflowy/shared/appflowy_cache_manager.dart';
|
import 'package:appflowy/shared/appflowy_cache_manager.dart';
|
||||||
import 'package:appflowy/startup/startup.dart';
|
import 'package:appflowy/startup/startup.dart';
|
||||||
import 'package:appflowy/util/share_log_files.dart';
|
import 'package:appflowy/util/share_log_files.dart';
|
||||||
|
import 'package:appflowy/workspace/presentation/home/toast.dart';
|
||||||
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/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
@ -71,9 +72,14 @@ class SupportSettingGroup extends StatelessWidget {
|
|||||||
maxLines: 4,
|
maxLines: 4,
|
||||||
),
|
),
|
||||||
actionButtonTitle: LocaleKeys.button_yes.tr(),
|
actionButtonTitle: LocaleKeys.button_yes.tr(),
|
||||||
actionButtonColor: Theme.of(context).colorScheme.error,
|
|
||||||
onActionButtonPressed: () async {
|
onActionButtonPressed: () async {
|
||||||
await getIt<FlowyCacheManager>().clearAllCache();
|
await getIt<FlowyCacheManager>().clearAllCache();
|
||||||
|
if (context.mounted) {
|
||||||
|
showSnackBarMessage(
|
||||||
|
context,
|
||||||
|
LocaleKeys.settings_files_clearCacheSuccess.tr(),
|
||||||
|
);
|
||||||
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
@ -13,6 +13,7 @@ enum FlowyOptionTileType {
|
|||||||
|
|
||||||
class FlowyOptionTile extends StatelessWidget {
|
class FlowyOptionTile extends StatelessWidget {
|
||||||
const FlowyOptionTile._({
|
const FlowyOptionTile._({
|
||||||
|
super.key,
|
||||||
required this.type,
|
required this.type,
|
||||||
this.showTopBorder = true,
|
this.showTopBorder = true,
|
||||||
this.showBottomBorder = true,
|
this.showBottomBorder = true,
|
||||||
@ -88,9 +89,11 @@ class FlowyOptionTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
factory FlowyOptionTile.checkbox({
|
factory FlowyOptionTile.checkbox({
|
||||||
|
Key? key,
|
||||||
required String text,
|
required String text,
|
||||||
required bool isSelected,
|
required bool isSelected,
|
||||||
required VoidCallback? onTap,
|
required VoidCallback? onTap,
|
||||||
|
Color? textColor,
|
||||||
Widget? leftIcon,
|
Widget? leftIcon,
|
||||||
Widget? content,
|
Widget? content,
|
||||||
bool showTopBorder = true,
|
bool showTopBorder = true,
|
||||||
@ -99,9 +102,11 @@ class FlowyOptionTile extends StatelessWidget {
|
|||||||
Color? backgroundColor,
|
Color? backgroundColor,
|
||||||
}) {
|
}) {
|
||||||
return FlowyOptionTile._(
|
return FlowyOptionTile._(
|
||||||
|
key: key,
|
||||||
type: FlowyOptionTileType.checkbox,
|
type: FlowyOptionTileType.checkbox,
|
||||||
isSelected: isSelected,
|
isSelected: isSelected,
|
||||||
text: text,
|
text: text,
|
||||||
|
textColor: textColor,
|
||||||
content: content,
|
content: content,
|
||||||
onTap: onTap,
|
onTap: onTap,
|
||||||
fontFamily: fontFamily,
|
fontFamily: fontFamily,
|
||||||
|
@ -337,6 +337,7 @@ class FieldController {
|
|||||||
...changeset.insertSorts.map((sort) => sort.sort.fieldId),
|
...changeset.insertSorts.map((sort) => sort.sort.fieldId),
|
||||||
...changeset.updateSorts.map((sort) => sort.fieldId),
|
...changeset.updateSorts.map((sort) => sort.fieldId),
|
||||||
...changeset.deleteSorts.map((sort) => sort.fieldId),
|
...changeset.deleteSorts.map((sort) => sort.fieldId),
|
||||||
|
...?_sortNotifier?.sorts.map((sort) => sort.fieldId),
|
||||||
]);
|
]);
|
||||||
|
|
||||||
final newFieldInfos = [...fieldInfos];
|
final newFieldInfos = [...fieldInfos];
|
||||||
@ -367,8 +368,8 @@ class FieldController {
|
|||||||
insertSortFromChangeset(newSortInfos, changeset);
|
insertSortFromChangeset(newSortInfos, changeset);
|
||||||
updateSortFromChangeset(newSortInfos, changeset);
|
updateSortFromChangeset(newSortInfos, changeset);
|
||||||
|
|
||||||
_sortNotifier?.sorts = newSortInfos;
|
|
||||||
updateFieldInfos(newSortInfos, changeset);
|
updateFieldInfos(newSortInfos, changeset);
|
||||||
|
_sortNotifier?.sorts = newSortInfos;
|
||||||
},
|
},
|
||||||
(err) => Log.error(err),
|
(err) => Log.error(err),
|
||||||
);
|
);
|
||||||
|
@ -32,7 +32,7 @@ class _CalculationSelectorState extends State<CalculationSelector> {
|
|||||||
onEnter: (_) => _setHovering(true),
|
onEnter: (_) => _setHovering(true),
|
||||||
onExit: (_) => _setHovering(false),
|
onExit: (_) => _setHovering(false),
|
||||||
child: AnimatedOpacity(
|
child: AnimatedOpacity(
|
||||||
duration: const Duration(milliseconds: 200),
|
duration: const Duration(milliseconds: 100),
|
||||||
opacity: widget.isSelected || _isHovering ? 1 : 0,
|
opacity: widget.isSelected || _isHovering ? 1 : 0,
|
||||||
child: FlowyButton(
|
child: FlowyButton(
|
||||||
radius: BorderRadius.zero,
|
radius: BorderRadius.zero,
|
||||||
|
@ -370,9 +370,6 @@ class _FieldDetailsEditorState extends State<FieldDetailsEditor> {
|
|||||||
Widget _addDeleteFieldButton() {
|
Widget _addDeleteFieldButton() {
|
||||||
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.field.isPrimary) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 0),
|
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 0),
|
||||||
child: FieldActionCell(
|
child: FieldActionCell(
|
||||||
@ -389,9 +386,6 @@ class _FieldDetailsEditorState extends State<FieldDetailsEditor> {
|
|||||||
Widget _addDuplicateFieldButton() {
|
Widget _addDuplicateFieldButton() {
|
||||||
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
builder: (context, state) {
|
builder: (context, state) {
|
||||||
if (state.field.isPrimary) {
|
|
||||||
return const SizedBox.shrink();
|
|
||||||
}
|
|
||||||
return Padding(
|
return Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 0),
|
padding: const EdgeInsets.fromLTRB(8.0, 4.0, 8.0, 0),
|
||||||
child: FieldActionCell(
|
child: FieldActionCell(
|
||||||
@ -533,41 +527,52 @@ class _SwitchFieldButtonState extends State<SwitchFieldButton> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return BlocBuilder<FieldEditorBloc, FieldEditorState>(
|
||||||
height: GridSize.popoverItemHeight,
|
builder: (context, state) {
|
||||||
child: AppFlowyPopover(
|
final bool isPrimary = state.field.isPrimary;
|
||||||
constraints: BoxConstraints.loose(const Size(460, 540)),
|
return SizedBox(
|
||||||
triggerActions: PopoverTriggerFlags.hover,
|
height: GridSize.popoverItemHeight,
|
||||||
mutex: widget.popoverMutex,
|
child: AppFlowyPopover(
|
||||||
controller: _popoverController,
|
constraints: BoxConstraints.loose(const Size(460, 540)),
|
||||||
offset: const Offset(8, 0),
|
triggerActions: isPrimary ? 0 : PopoverTriggerFlags.hover,
|
||||||
margin: const EdgeInsets.all(8),
|
mutex: widget.popoverMutex,
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
controller: _popoverController,
|
||||||
return FieldTypeList(
|
offset: const Offset(8, 0),
|
||||||
onSelectField: (newFieldType) {
|
margin: const EdgeInsets.all(8),
|
||||||
context
|
popupBuilder: (BuildContext popoverContext) {
|
||||||
.read<FieldEditorBloc>()
|
return FieldTypeList(
|
||||||
.add(FieldEditorEvent.switchFieldType(newFieldType));
|
onSelectField: (newFieldType) {
|
||||||
|
context
|
||||||
|
.read<FieldEditorBloc>()
|
||||||
|
.add(FieldEditorEvent.switchFieldType(newFieldType));
|
||||||
|
},
|
||||||
|
);
|
||||||
},
|
},
|
||||||
);
|
child: Padding(
|
||||||
},
|
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
||||||
child: Padding(
|
child: FlowyButton(
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8.0),
|
onTap: () {
|
||||||
child: _buildMoreButton(context),
|
if (!isPrimary) {
|
||||||
),
|
_popoverController.show();
|
||||||
),
|
}
|
||||||
);
|
},
|
||||||
}
|
text: FlowyText.medium(
|
||||||
|
state.field.fieldType.i18n,
|
||||||
Widget _buildMoreButton(BuildContext context) {
|
color: isPrimary ? Theme.of(context).disabledColor : null,
|
||||||
final bloc = context.read<FieldEditorBloc>();
|
),
|
||||||
return FlowyButton(
|
leftIcon: FlowySvg(
|
||||||
onTap: () => _popoverController.show(),
|
state.field.fieldType.svgData,
|
||||||
text: FlowyText.medium(
|
color: isPrimary ? Theme.of(context).disabledColor : null,
|
||||||
bloc.state.field.fieldType.i18n,
|
),
|
||||||
),
|
rightIcon: FlowySvg(
|
||||||
leftIcon: FlowySvg(bloc.state.field.fieldType.svgData),
|
FlowySvgs.more_s,
|
||||||
rightIcon: const FlowySvg(FlowySvgs.more_s),
|
color: isPrimary ? Theme.of(context).disabledColor : null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/cell/bloc/checklist_cell_bloc.dart';
|
import 'package:appflowy/plugins/database/application/cell/bloc/checklist_cell_bloc.dart';
|
||||||
|
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
|
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_cell_editor.dart';
|
||||||
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
|
import 'package:appflowy/plugins/database/widgets/cell_editor/checklist_progress_bar.dart';
|
||||||
|
import 'package:appflowy/plugins/database/widgets/row/cells/cell_container.dart';
|
||||||
import 'package:appflowy_popover/appflowy_popover.dart';
|
import 'package:appflowy_popover/appflowy_popover.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../editable_cell_skeleton/checklist.dart';
|
import '../editable_cell_skeleton/checklist.dart';
|
||||||
@ -25,6 +26,7 @@ class DesktopGridChecklistCellSkin extends IEditableChecklistCellSkin {
|
|||||||
constraints: BoxConstraints.loose(const Size(360, 400)),
|
constraints: BoxConstraints.loose(const Size(360, 400)),
|
||||||
direction: PopoverDirection.bottomWithLeftAligned,
|
direction: PopoverDirection.bottomWithLeftAligned,
|
||||||
triggerActions: PopoverTriggerFlags.none,
|
triggerActions: PopoverTriggerFlags.none,
|
||||||
|
skipTraversal: true,
|
||||||
popupBuilder: (BuildContext popoverContext) {
|
popupBuilder: (BuildContext popoverContext) {
|
||||||
WidgetsBinding.instance.addPostFrameCallback((_) {
|
WidgetsBinding.instance.addPostFrameCallback((_) {
|
||||||
cellContainerNotifier.isFocus = true;
|
cellContainerNotifier.isFocus = true;
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
import 'package:appflowy/core/helpers/url_launcher.dart';
|
|
||||||
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/plugins/database/application/cell/bloc/url_cell_bloc.dart';
|
import 'package:appflowy/plugins/database/application/cell/bloc/url_cell_bloc.dart';
|
||||||
@ -177,21 +176,11 @@ class _VisitURLAccessoryState extends State<_VisitURLAccessory>
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
bool enable() {
|
bool enable() => widget.cellDataNotifier.value.isNotEmpty;
|
||||||
return widget.cellDataNotifier.value.isNotEmpty;
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void onTap() {
|
void onTap() =>
|
||||||
final content = widget.cellDataNotifier.value;
|
openUrlCellLink(widget.cellDataNotifier.value);
|
||||||
if (content.isEmpty) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
final shouldAddScheme =
|
|
||||||
!['http', 'https'].any((pattern) => content.startsWith(pattern));
|
|
||||||
final url = shouldAddScheme ? 'http://$content' : content;
|
|
||||||
afLaunchUrlString(url);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class _URLAccessoryIconContainer extends StatelessWidget {
|
class _URLAccessoryIconContainer extends StatelessWidget {
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
|
|
||||||
|
import 'package:appflowy/core/helpers/url_launcher.dart';
|
||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
@ -15,6 +16,9 @@ import '../desktop_row_detail/desktop_row_detail_url_cell.dart';
|
|||||||
import '../mobile_grid/mobile_grid_url_cell.dart';
|
import '../mobile_grid/mobile_grid_url_cell.dart';
|
||||||
import '../mobile_row_detail/mobile_row_detail_url_cell.dart';
|
import '../mobile_row_detail/mobile_row_detail_url_cell.dart';
|
||||||
|
|
||||||
|
const regexUrl =
|
||||||
|
r"[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:._\+-~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:_\+.~#?&\/\/=]*)";
|
||||||
|
|
||||||
abstract class IEditableURLCellSkin {
|
abstract class IEditableURLCellSkin {
|
||||||
const IEditableURLCellSkin();
|
const IEditableURLCellSkin();
|
||||||
|
|
||||||
@ -130,3 +134,24 @@ class _GridURLCellState extends GridEditableTextCell<EditableURLCell> {
|
|||||||
@override
|
@override
|
||||||
String? onCopy() => cellBloc.state.content;
|
String? onCopy() => cellBloc.state.content;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void openUrlCellLink(String content) {
|
||||||
|
if (RegExp(regexUrl).hasMatch(content)) {
|
||||||
|
const linkPrefix = [
|
||||||
|
'http://',
|
||||||
|
'https://',
|
||||||
|
'file://',
|
||||||
|
'ftp://',
|
||||||
|
'ftps://',
|
||||||
|
'mailto:',
|
||||||
|
];
|
||||||
|
final shouldAddScheme =
|
||||||
|
!linkPrefix.any((pattern) => content.startsWith(pattern));
|
||||||
|
final url = shouldAddScheme ? 'https://$content' : content;
|
||||||
|
afLaunchUrlString(url);
|
||||||
|
} else {
|
||||||
|
afLaunchUrlString(
|
||||||
|
"https://www.google.com/search?q=${Uri.encodeComponent(content)}",
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,9 @@
|
|||||||
import 'dart:async';
|
import 'dart:async';
|
||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
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/plugins/database/application/cell/cell_controller_builder.dart';
|
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
||||||
@ -11,11 +14,10 @@ import 'package:easy_localization/easy_localization.dart';
|
|||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra/theme_extension.dart';
|
import 'package:flowy_infra/theme_extension.dart';
|
||||||
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
import 'package:flutter/services.dart';
|
|
||||||
import 'package:flutter_bloc/flutter_bloc.dart';
|
import 'package:flutter_bloc/flutter_bloc.dart';
|
||||||
|
|
||||||
import '../../application/cell/bloc/checklist_cell_bloc.dart';
|
import '../../application/cell/bloc/checklist_cell_bloc.dart';
|
||||||
|
|
||||||
import 'checklist_progress_bar.dart';
|
import 'checklist_progress_bar.dart';
|
||||||
|
|
||||||
class ChecklistCellEditor extends StatefulWidget {
|
class ChecklistCellEditor extends StatefulWidget {
|
||||||
@ -189,7 +191,9 @@ class _ChecklistItemState extends State<ChecklistItem> {
|
|||||||
void didUpdateWidget(ChecklistItem oldWidget) {
|
void didUpdateWidget(ChecklistItem oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
if (widget.task.data.name != oldWidget.task.data.name) {
|
if (widget.task.data.name != oldWidget.task.data.name) {
|
||||||
|
final selection = _textController.selection;
|
||||||
_textController.text = widget.task.data.name;
|
_textController.text = widget.task.data.name;
|
||||||
|
_textController.selection = selection;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -234,6 +238,10 @@ class _ChecklistItemState extends State<ChecklistItem> {
|
|||||||
else
|
else
|
||||||
const SingleActivator(LogicalKeyboardKey.enter, control: true):
|
const SingleActivator(LogicalKeyboardKey.enter, control: true):
|
||||||
const _SelectTaskIntent(),
|
const _SelectTaskIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowUp):
|
||||||
|
const PreviousFocusIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowDown):
|
||||||
|
const NextFocusIntent(),
|
||||||
},
|
},
|
||||||
descendantsAreTraversable: false,
|
descendantsAreTraversable: false,
|
||||||
child: Container(
|
child: Container(
|
||||||
@ -261,15 +269,24 @@ class _ChecklistItemState extends State<ChecklistItem> {
|
|||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: Shortcuts(
|
child: Shortcuts(
|
||||||
shortcuts: const {
|
shortcuts: {
|
||||||
SingleActivator(LogicalKeyboardKey.space):
|
const SingleActivator(LogicalKeyboardKey.space):
|
||||||
DoNothingAndStopPropagationIntent(),
|
const DoNothingAndStopPropagationIntent(),
|
||||||
SingleActivator(LogicalKeyboardKey.delete):
|
const SingleActivator(LogicalKeyboardKey.delete):
|
||||||
DoNothingAndStopPropagationIntent(),
|
const DoNothingAndStopPropagationIntent(),
|
||||||
SingleActivator(LogicalKeyboardKey.enter):
|
if (Platform.isMacOS)
|
||||||
DoNothingAndStopPropagationIntent(),
|
LogicalKeySet(
|
||||||
SingleActivator(LogicalKeyboardKey.escape):
|
LogicalKeyboardKey.fn,
|
||||||
_EndEditingTaskIntent(),
|
LogicalKeyboardKey.backspace,
|
||||||
|
): const DoNothingAndStopPropagationIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.enter):
|
||||||
|
const DoNothingAndStopPropagationIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.escape):
|
||||||
|
const _EndEditingTaskIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowUp):
|
||||||
|
const DoNothingAndStopPropagationIntent(),
|
||||||
|
const SingleActivator(LogicalKeyboardKey.arrowDown):
|
||||||
|
const DoNothingAndStopPropagationIntent(),
|
||||||
},
|
},
|
||||||
child: TextField(
|
child: TextField(
|
||||||
controller: _textController,
|
controller: _textController,
|
||||||
@ -345,12 +362,11 @@ class NewTaskItem extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _NewTaskItemState extends State<NewTaskItem> {
|
class _NewTaskItemState extends State<NewTaskItem> {
|
||||||
late final TextEditingController _textEditingController;
|
final _textEditingController = TextEditingController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_textEditingController = TextEditingController();
|
|
||||||
if (widget.focusNode.canRequestFocus) {
|
if (widget.focusNode.canRequestFocus) {
|
||||||
widget.focusNode.requestFocus();
|
widget.focusNode.requestFocus();
|
||||||
}
|
}
|
||||||
@ -385,15 +401,13 @@ class _NewTaskItemState extends State<NewTaskItem> {
|
|||||||
hintText: LocaleKeys.grid_checklist_addNew.tr(),
|
hintText: LocaleKeys.grid_checklist_addNew.tr(),
|
||||||
),
|
),
|
||||||
onSubmitted: (taskDescription) {
|
onSubmitted: (taskDescription) {
|
||||||
if (taskDescription.trim().isNotEmpty) {
|
if (taskDescription.isNotEmpty) {
|
||||||
context.read<ChecklistCellBloc>().add(
|
context
|
||||||
ChecklistCellEvent.createNewTask(
|
.read<ChecklistCellBloc>()
|
||||||
taskDescription.trim(),
|
.add(ChecklistCellEvent.createNewTask(taskDescription));
|
||||||
),
|
_textEditingController.clear();
|
||||||
);
|
|
||||||
}
|
}
|
||||||
widget.focusNode.requestFocus();
|
widget.focusNode.requestFocus();
|
||||||
_textEditingController.clear();
|
|
||||||
},
|
},
|
||||||
onChanged: (value) => setState(() {}),
|
onChanged: (value) => setState(() {}),
|
||||||
),
|
),
|
||||||
@ -409,16 +423,17 @@ class _NewTaskItemState extends State<NewTaskItem> {
|
|||||||
: Theme.of(context).colorScheme.primaryContainer,
|
: Theme.of(context).colorScheme.primaryContainer,
|
||||||
fontColor: Theme.of(context).colorScheme.onPrimary,
|
fontColor: Theme.of(context).colorScheme.onPrimary,
|
||||||
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 3),
|
||||||
onPressed: () {
|
onPressed: _textEditingController.text.isEmpty
|
||||||
final text = _textEditingController.text.trim();
|
? null
|
||||||
if (text.isNotEmpty) {
|
: () {
|
||||||
context.read<ChecklistCellBloc>().add(
|
context.read<ChecklistCellBloc>().add(
|
||||||
ChecklistCellEvent.createNewTask(text),
|
ChecklistCellEvent.createNewTask(
|
||||||
);
|
_textEditingController.text,
|
||||||
}
|
),
|
||||||
widget.focusNode.requestFocus();
|
);
|
||||||
_textEditingController.clear();
|
widget.focusNode.requestFocus();
|
||||||
},
|
_textEditingController.clear();
|
||||||
|
},
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -150,6 +150,7 @@ void _showEditSortPanelFromToolbar(
|
|||||||
showDragHandle: true,
|
showDragHandle: true,
|
||||||
showDivider: false,
|
showDivider: false,
|
||||||
useSafeArea: false,
|
useSafeArea: false,
|
||||||
|
backgroundColor: Theme.of(context).colorScheme.background,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
return BlocProvider.value(
|
return BlocProvider.value(
|
||||||
value: context.read<SortEditorBloc>(),
|
value: context.read<SortEditorBloc>(),
|
||||||
|
@ -86,6 +86,13 @@ class ImagePlaceholderState extends State<ImagePlaceholder> {
|
|||||||
popupBuilder: (context) {
|
popupBuilder: (context) {
|
||||||
return UploadImageMenu(
|
return UploadImageMenu(
|
||||||
limitMaximumImageSize: !_isLocalMode(),
|
limitMaximumImageSize: !_isLocalMode(),
|
||||||
|
supportTypes: const [
|
||||||
|
UploadImageType.local,
|
||||||
|
UploadImageType.url,
|
||||||
|
UploadImageType.unsplash,
|
||||||
|
UploadImageType.openAI,
|
||||||
|
UploadImageType.stabilityAI,
|
||||||
|
],
|
||||||
onSelectedLocalImage: (path) {
|
onSelectedLocalImage: (path) {
|
||||||
controller.close();
|
controller.close();
|
||||||
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
WidgetsBinding.instance.addPostFrameCallback((timeStamp) async {
|
||||||
|
@ -1,7 +1,8 @@
|
|||||||
import 'package:appflowy_popover/src/layout.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
|
|
||||||
|
import 'package:appflowy_popover/src/layout.dart';
|
||||||
|
|
||||||
import 'mask.dart';
|
import 'mask.dart';
|
||||||
import 'mutex.dart';
|
import 'mutex.dart';
|
||||||
|
|
||||||
@ -90,6 +91,8 @@ class Popover extends StatefulWidget {
|
|||||||
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
||||||
final PopoverClickHandler clickHandler;
|
final PopoverClickHandler clickHandler;
|
||||||
|
|
||||||
|
final bool skipTraversal;
|
||||||
|
|
||||||
/// The content area of the popover.
|
/// The content area of the popover.
|
||||||
final Widget child;
|
final Widget child;
|
||||||
|
|
||||||
@ -110,6 +113,7 @@ class Popover extends StatefulWidget {
|
|||||||
this.canClose,
|
this.canClose,
|
||||||
this.asBarrier = false,
|
this.asBarrier = false,
|
||||||
this.clickHandler = PopoverClickHandler.listener,
|
this.clickHandler = PopoverClickHandler.listener,
|
||||||
|
this.skipTraversal = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -158,6 +162,7 @@ class PopoverState extends State<Popover> {
|
|||||||
popupBuilder: widget.popupBuilder,
|
popupBuilder: widget.popupBuilder,
|
||||||
onClose: () => close(),
|
onClose: () => close(),
|
||||||
onCloseAll: () => _removeRootOverlay(),
|
onCloseAll: () => _removeRootOverlay(),
|
||||||
|
skipTraversal: widget.skipTraversal,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -263,6 +268,7 @@ class PopoverContainer extends StatefulWidget {
|
|||||||
final EdgeInsets windowPadding;
|
final EdgeInsets windowPadding;
|
||||||
final void Function() onClose;
|
final void Function() onClose;
|
||||||
final void Function() onCloseAll;
|
final void Function() onCloseAll;
|
||||||
|
final bool skipTraversal;
|
||||||
|
|
||||||
const PopoverContainer({
|
const PopoverContainer({
|
||||||
super.key,
|
super.key,
|
||||||
@ -273,6 +279,7 @@ class PopoverContainer extends StatefulWidget {
|
|||||||
required this.windowPadding,
|
required this.windowPadding,
|
||||||
required this.onClose,
|
required this.onClose,
|
||||||
required this.onCloseAll,
|
required this.onCloseAll,
|
||||||
|
required this.skipTraversal,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -293,6 +300,7 @@ class PopoverContainerState extends State<PopoverContainer> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Focus(
|
return Focus(
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
|
skipTraversal: widget.skipTraversal,
|
||||||
child: CustomSingleChildLayout(
|
child: CustomSingleChildLayout(
|
||||||
delegate: PopoverLayoutDelegate(
|
delegate: PopoverLayoutDelegate(
|
||||||
direction: widget.direction,
|
direction: widget.direction,
|
||||||
|
@ -26,6 +26,10 @@ class AppFlowyPopover extends StatelessWidget {
|
|||||||
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
/// the conflict won't be resolve by using Listener, we want these two gestures exclusive.
|
||||||
final PopoverClickHandler clickHandler;
|
final PopoverClickHandler clickHandler;
|
||||||
|
|
||||||
|
/// If true the popover will not participate in focus traversal.
|
||||||
|
///
|
||||||
|
final bool skipTraversal;
|
||||||
|
|
||||||
const AppFlowyPopover({
|
const AppFlowyPopover({
|
||||||
super.key,
|
super.key,
|
||||||
required this.child,
|
required this.child,
|
||||||
@ -43,6 +47,7 @@ class AppFlowyPopover extends StatelessWidget {
|
|||||||
this.windowPadding = const EdgeInsets.all(8.0),
|
this.windowPadding = const EdgeInsets.all(8.0),
|
||||||
this.decoration,
|
this.decoration,
|
||||||
this.clickHandler = PopoverClickHandler.listener,
|
this.clickHandler = PopoverClickHandler.listener,
|
||||||
|
this.skipTraversal = false,
|
||||||
});
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -58,6 +63,7 @@ class AppFlowyPopover extends StatelessWidget {
|
|||||||
windowPadding: windowPadding,
|
windowPadding: windowPadding,
|
||||||
offset: offset,
|
offset: offset,
|
||||||
clickHandler: clickHandler,
|
clickHandler: clickHandler,
|
||||||
|
skipTraversal: skipTraversal,
|
||||||
popupBuilder: (context) {
|
popupBuilder: (context) {
|
||||||
return _PopoverContainer(
|
return _PopoverContainer(
|
||||||
constraints: constraints,
|
constraints: constraints,
|
||||||
|
@ -1,12 +1,13 @@
|
|||||||
import 'dart:io';
|
import 'dart:io';
|
||||||
|
|
||||||
|
import 'package:flutter/material.dart';
|
||||||
|
|
||||||
import 'package:flowy_infra/size.dart';
|
import 'package:flowy_infra/size.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
import 'package:flowy_infra_ui/style_widget/hover.dart';
|
||||||
import 'package:flowy_infra_ui/style_widget/text.dart';
|
import 'package:flowy_infra_ui/style_widget/text.dart';
|
||||||
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
|
||||||
import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
|
import 'package:flowy_infra_ui/widget/ignore_parent_gesture.dart';
|
||||||
import 'package:flowy_infra_ui/widget/spacing.dart';
|
import 'package:flowy_infra_ui/widget/spacing.dart';
|
||||||
import 'package:flutter/material.dart';
|
|
||||||
|
|
||||||
class FlowyButton extends StatelessWidget {
|
class FlowyButton extends StatelessWidget {
|
||||||
final Widget text;
|
final Widget text;
|
||||||
@ -213,6 +214,7 @@ class FlowyTextButton extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
|
|
||||||
child = RawMaterialButton(
|
child = RawMaterialButton(
|
||||||
|
focusNode: FocusNode(skipTraversal: onPressed == null),
|
||||||
hoverElevation: 0,
|
hoverElevation: 0,
|
||||||
highlightElevation: 0,
|
highlightElevation: 0,
|
||||||
shape: RoundedRectangleBorder(borderRadius: radius ?? Corners.s6Border),
|
shape: RoundedRectangleBorder(borderRadius: radius ?? Corners.s6Border),
|
||||||
@ -237,6 +239,10 @@ class FlowyTextButton extends StatelessWidget {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (onPressed == null) {
|
||||||
|
child = ExcludeFocus(child: child);
|
||||||
|
}
|
||||||
|
|
||||||
return child;
|
return child;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1101,10 +1101,10 @@ packages:
|
|||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
name: markdown
|
name: markdown
|
||||||
sha256: "1b134d9f8ff2da15cb298efe6cd8b7d2a78958c1b00384ebcbdf13fe340a6c90"
|
sha256: ef2a1298144e3f985cc736b22e0ccdaf188b5b3970648f2d9dc13efd1d9df051
|
||||||
url: "https://pub.dev"
|
url: "https://pub.dev"
|
||||||
source: hosted
|
source: hosted
|
||||||
version: "7.2.1"
|
version: "7.2.2"
|
||||||
matcher:
|
matcher:
|
||||||
dependency: transitive
|
dependency: transitive
|
||||||
description:
|
description:
|
||||||
|
@ -463,7 +463,7 @@
|
|||||||
"exportFileFail": "Export file failed!",
|
"exportFileFail": "Export file failed!",
|
||||||
"export": "Export",
|
"export": "Export",
|
||||||
"clearCache": "Clear cache",
|
"clearCache": "Clear cache",
|
||||||
"clearCacheDesc": "Clear the cache including the images, fonts, and other temporary files. This will not delete your data.",
|
"clearCacheDesc": "If you encounter issues with images not loading or fonts not displaying correctly, try clearing your cache. This action will not remove your user data.",
|
||||||
"areYouSureToClearCache": "Are you sure to clear the cache?",
|
"areYouSureToClearCache": "Are you sure to clear the cache?",
|
||||||
"clearCacheSuccess": "Cache cleared successfully!"
|
"clearCacheSuccess": "Cache cleared successfully!"
|
||||||
},
|
},
|
||||||
@ -679,7 +679,8 @@
|
|||||||
"cannotFindCreatableField": "Cannot find a suitable field to sort by",
|
"cannotFindCreatableField": "Cannot find a suitable field to sort by",
|
||||||
"deleteAllSorts": "Delete all sorts",
|
"deleteAllSorts": "Delete all sorts",
|
||||||
"addSort": "Add new sort",
|
"addSort": "Add new sort",
|
||||||
"removeSorting": "Would you like to remove sorting?"
|
"removeSorting": "Would you like to remove sorting?",
|
||||||
|
"fieldInUse": "You are already sorting by this field"
|
||||||
},
|
},
|
||||||
"row": {
|
"row": {
|
||||||
"duplicate": "Duplicate",
|
"duplicate": "Duplicate",
|
||||||
|
Loading…
Reference in New Issue
Block a user