Merge pull request #1091 from AppFlowy-IO/fix/appflowy_overlay_bugs

Fix/appflowy overlay bugs
This commit is contained in:
Nathan.fooo 2022-09-19 17:46:21 +08:00 committed by GitHub
commit 5896855dda
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
37 changed files with 534 additions and 499 deletions

View File

@ -213,8 +213,8 @@
"aquaColor": "Aqua",
"blueColor": "Blue",
"deleteTag": "Delete tag",
"colorPannelTitle": "Colors",
"pannelTitle": "Select an option or create one",
"colorPanelTitle": "Colors",
"panelTitle": "Select an option or create one",
"searchOption": "Search for an option"
},
"menuName": "Grid"

View File

@ -201,8 +201,8 @@
"aquaColor": "Agua",
"blueColor": "Azul",
"deleteTag": "Borrar etiqueta",
"colorPannelTitle": "Colores",
"pannelTitle": "Selecciona una opción o crea una",
"colorPanelTitle": "Colores",
"panelTitle": "Selecciona una opción o crea una",
"searchOption": "Buscar una opción"
},
"menuName": "Grid"
@ -218,4 +218,4 @@
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
}
}
}

View File

@ -199,8 +199,8 @@
"aquaColor": "Aqua",
"blueColor": "Bleu",
"deleteTag": "Supprimer l'étiquette",
"colorPannelTitle": "Couleurs",
"pannelTitle": "Sélectionnez une option ou créez-en une",
"colorPanelTitle": "Couleurs",
"panelTitle": "Sélectionnez une option ou créez-en une",
"searchOption": "Rechercher une option"
},
"menuName": "Grille"
@ -212,4 +212,4 @@
"timeHintTextInTwentyFourHour": "12:00"
}
}
}
}

View File

@ -202,8 +202,8 @@
"aquaColor": "Air",
"blueColor": "Biru",
"deleteTag": "Hapus tag",
"colorPannelTitle": "Warna",
"pannelTitle": "Pilih opsi atau buat baru",
"colorPanelTitle": "Warna",
"panelTitle": "Pilih opsi atau buat baru",
"searchOption": "Cari opsi"
},
"menuName": "Grid"

View File

@ -191,8 +191,8 @@
"aquaColor": "水色",
"blueColor": "青",
"deleteTag": "選択候補を削除",
"colorPannelTitle": "色",
"pannelTitle": "選択候補を検索 または 作成する",
"colorPanelTitle": "色",
"panelTitle": "選択候補を検索 または 作成する",
"searchOption": "選択候補を検索"
}
},

View File

@ -1,212 +1,211 @@
{
"appName": "AppFlowy",
"defaultUsername": "Я",
"welcomeText": "Добро пожаловать в @:appName",
"githubStarText": "Поставить звезду на GitHub",
"subscribeNewsletterText": "Подписаться на рассылку",
"letsGoButtonText": "Начнём",
"title": "Заголовок",
"signUp": {
"buttonText": "Зарегистрироваться",
"title": "Регистрация в @:appName",
"getStartedText": "Начать",
"emptyPasswordError": "Пароль не может быть пустым",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают",
"alreadyHaveAnAccount": "Уже есть аккаунт?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"repeatPasswordHint": "Повторите пароль"
},
"signIn": {
"loginTitle": "Войти в @:appName",
"loginButtonText": "Войти",
"buttonText": "Авторизация",
"forgotPassword": "Забыли пароль?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"dontHaveAnAccount": "Нет аккаунта?",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают"
},
"workspace": {
"create": "Создать рабочее пространство",
"hint": "рабочее пространство",
"notFoundError": "Нет такого рабочего пространства"
},
"shareAction": {
"buttonText": "Поделиться",
"workInProgress": "В разработке",
"markdown": "Markdown",
"copyLink": "Скопировать ссылку"
},
"disclosureAction": {
"rename": "Переименовать",
"delete": "Удалить",
"duplicate": "Дублировать"
},
"blankPageTitle": "Пустая страница",
"newPageText": "Новая страница",
"trash": {
"text": "Корзина",
"restoreAll": "Восстановить всё",
"deleteAll": "Очистить",
"pageHeader": {
"fileName": "Имя",
"lastModified": "Последнее изменение",
"created": "Создан"
}
},
"deletePagePrompt": {
"text": "Эта страница в Корзине",
"restore": "Восстановить страницу",
"deletePermanent": "Удалить навсегда"
},
"dialogCreatePageNameHint": "Имя",
"questionBubble": {
"whatsNew": "Что нового?",
"help": "Помощь",
"debug": {
"name": "Отладочная информация",
"success": "Скопировано в буфер обмена!",
"fail": "Не получилось скопировать"
}
},
"menuAppHeader": {
"addPageTooltip": "Быстро добавить новую страницу",
"defaultNewPageName": "Без заголовка",
"renameDialog": "Переименовать"
},
"toolbar": {
"undo": "Отменить",
"redo": "Повторить",
"bold": "Жирный",
"italic": "Курсив",
"underline": "Подчёркнутый",
"strike": "Зачёркнутый",
"numList": "Нумерованный список",
"bulletList": "Маркированный список",
"checkList": "Список To-Do",
"inlineCode": "Код",
"quote": "Цитата",
"header": "Заголовок",
"highlight": "Выделение"
},
"tooltip": {
"lightMode": "Переключиться в светлую тему",
"darkMode": "Переключиться в тёмную тему"
},
"contactsPage": {
"title": "Контакты",
"whatsHappening": "Что происходит на этой неделе?",
"addContact": "Новый контакт",
"editContact": "Редактировать"
},
"button": {
"OK": "OK",
"Cancel": "Отмена",
"signIn": "Войти",
"signOut": "Выйти",
"complete": "Завершить",
"save": "Сохранить"
},
"label": {
"welcome": "Добро пожаловать!",
"firstName": "Имя",
"middleName": "Отчество",
"lastName": "Фамилия",
"stepX": "Этап {X}"
},
"oAuth": {
"err": {
"failedTitle": "Ошибка подключения к аккаунту.",
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
},
"google": {
"title": "Вход через Google",
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
"instruction3": "Пройдите по ссылке и введите этот код:",
"instruction4": "Нажмите на кнопку, когда завершите вход:"
}
},
"settings": {
"title": "Настройки",
"menu": {
"appearance": "Внешний вид",
"language": "Язык",
"open": "Открыть настройки"
},
"appearance": {
"lightLabel": "Светлая тема",
"darkLabel": "Тёмная тема"
}
},
"grid": {
"settings": {
"filter": "Фильтр",
"sortBy": "Сортировать",
"Properties": "Свойства"
},
"field": {
"hide": "Скрыть",
"insertLeft": "Вставить слева",
"insertRight": "Вставить справа",
"duplicate": "Дублировать",
"delete": "Удалить",
"textFieldName": "Текст",
"checkboxFieldName": "Checkbox",
"dateFieldName": "Дата",
"numberFieldName": "Число",
"singleSelectFieldName": "Выбор",
"multiSelectFieldName": "Выбор многих",
"urlFieldName": "URL",
"numberFormat": " Формат числа",
"dateFormat": " Формат даты",
"includeTime": " Время",
"dateFormatFriendly": "День Месяц, Год",
"dateFormatISO": "Год-Месяц-День",
"dateFormatLocal": "Год/Месяц/День",
"dateFormatUS": "Год/Месяц/День",
"timeFormat": " Форматировать время",
"invalidTimeFormat": "Неверный формат",
"timeFormatTwelveHour": "12 часов",
"timeFormatTwentyFourHour": "24 часа",
"addSelectOption": "Добавить вариант",
"optionTitle": "Варианты",
"addOption": "Добавить",
"editProperty": "Редактировать свойство"
},
"row": {
"duplicate": "Дублировать",
"delete": "Удалить",
"textPlaceholder": "Пусто",
"copyProperty": "Свойство скопировано"
},
"selectOption": {
"create": "Создать",
"purpleColor": "Фиолетовый",
"pinkColor": "Розовый",
"lightPinkColor": "Светло-розовый",
"orangeColor": "Оранжевый",
"yellowColor": "Желтый",
"limeColor": "Ярко-зелёный",
"greenColor": "Зелёный",
"aquaColor": "Морской волны",
"blueColor": "Синий",
"deleteTag": "Удалить вариант",
"colorPannelTitle": "Цвета",
"pannelTitle": "Выберите или создайте вариант",
"searchOption": "Поиск"
},
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
}
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
"appName": "AppFlowy",
"defaultUsername": "Я",
"welcomeText": "Добро пожаловать в @:appName",
"githubStarText": "Поставить звезду на GitHub",
"subscribeNewsletterText": "Подписаться на рассылку",
"letsGoButtonText": "Начнём",
"title": "Заголовок",
"signUp": {
"buttonText": "Зарегистрироваться",
"title": "Регистрация в @:appName",
"getStartedText": "Начать",
"emptyPasswordError": "Пароль не может быть пустым",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают",
"alreadyHaveAnAccount": "Уже есть аккаунт?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"repeatPasswordHint": "Повторите пароль"
},
"signIn": {
"loginTitle": "Войти в @:appName",
"loginButtonText": "Войти",
"buttonText": "Авторизация",
"forgotPassword": "Забыли пароль?",
"emailHint": "Электронная почта",
"passwordHint": "Пароль",
"dontHaveAnAccount": "Нет аккаунта?",
"repeatPasswordEmptyError": "Повтор пароля не может быть пустым",
"unmatchedPasswordError": "Пароли не совпадают"
},
"workspace": {
"create": "Создать рабочее пространство",
"hint": "рабочее пространство",
"notFoundError": "Нет такого рабочего пространства"
},
"shareAction": {
"buttonText": "Поделиться",
"workInProgress": "В разработке",
"markdown": "Markdown",
"copyLink": "Скопировать ссылку"
},
"disclosureAction": {
"rename": "Переименовать",
"delete": "Удалить",
"duplicate": "Дублировать"
},
"blankPageTitle": "Пустая страница",
"newPageText": "Новая страница",
"trash": {
"text": "Корзина",
"restoreAll": "Восстановить всё",
"deleteAll": "Очистить",
"pageHeader": {
"fileName": "Имя",
"lastModified": "Последнее изменение",
"created": "Создан"
}
},
"deletePagePrompt": {
"text": "Эта страница в Корзине",
"restore": "Восстановить страницу",
"deletePermanent": "Удалить навсегда"
},
"dialogCreatePageNameHint": "Имя",
"questionBubble": {
"whatsNew": "Что нового?",
"help": "Помощь",
"debug": {
"name": "Отладочная информация",
"success": "Скопировано в буфер обмена!",
"fail": "Не получилось скопировать"
}
},
"menuAppHeader": {
"addPageTooltip": "Быстро добавить новую страницу",
"defaultNewPageName": "Без заголовка",
"renameDialog": "Переименовать"
},
"toolbar": {
"undo": "Отменить",
"redo": "Повторить",
"bold": "Жирный",
"italic": "Курсив",
"underline": "Подчёркнутый",
"strike": "Зачёркнутый",
"numList": "Нумерованный список",
"bulletList": "Маркированный список",
"checkList": "Список To-Do",
"inlineCode": "Код",
"quote": "Цитата",
"header": "Заголовок",
"highlight": "Выделение"
},
"tooltip": {
"lightMode": "Переключиться в светлую тему",
"darkMode": "Переключиться в тёмную тему"
},
"contactsPage": {
"title": "Контакты",
"whatsHappening": "Что происходит на этой неделе?",
"addContact": "Новый контакт",
"editContact": "Редактировать"
},
"button": {
"OK": "OK",
"Cancel": "Отмена",
"signIn": "Войти",
"signOut": "Выйти",
"complete": "Завершить",
"save": "Сохранить"
},
"label": {
"welcome": "Добро пожаловать!",
"firstName": "Имя",
"middleName": "Отчество",
"lastName": "Фамилия",
"stepX": "Этап {X}"
},
"oAuth": {
"err": {
"failedTitle": "Ошибка подключения к аккаунту.",
"failedMsg": "Убедитесь, что вы завершили вход в своём браузере."
},
"google": {
"title": "Вход через Google",
"instruction1": "Чтобы импортировать ваши Google Контакты, вам нужно будет авторизовать приложение через браузер.",
"instruction2": "Скопируйте этот код в буфер обмена (нажав кнопку или выделив текст):",
"instruction3": "Пройдите по ссылке и введите этот код:",
"instruction4": "Нажмите на кнопку, когда завершите вход:"
}
},
"settings": {
"title": "Настройки",
"menu": {
"appearance": "Внешний вид",
"language": "Язык",
"open": "Открыть настройки"
},
"appearance": {
"lightLabel": "Светлая тема",
"darkLabel": "Тёмная тема"
}
},
"grid": {
"settings": {
"filter": "Фильтр",
"sortBy": "Сортировать",
"Properties": "Свойства"
},
"field": {
"hide": "Скрыть",
"insertLeft": "Вставить слева",
"insertRight": "Вставить справа",
"duplicate": "Дублировать",
"delete": "Удалить",
"textFieldName": "Текст",
"checkboxFieldName": "Checkbox",
"dateFieldName": "Дата",
"numberFieldName": "Число",
"singleSelectFieldName": "Выбор",
"multiSelectFieldName": "Выбор многих",
"urlFieldName": "URL",
"numberFormat": " Формат числа",
"dateFormat": " Формат даты",
"includeTime": " Время",
"dateFormatFriendly": "День Месяц, Год",
"dateFormatISO": "Год-Месяц-День",
"dateFormatLocal": "Год/Месяц/День",
"dateFormatUS": "Год/Месяц/День",
"timeFormat": " Форматировать время",
"invalidTimeFormat": "Неверный формат",
"timeFormatTwelveHour": "12 часов",
"timeFormatTwentyFourHour": "24 часа",
"addSelectOption": "Добавить вариант",
"optionTitle": "Варианты",
"addOption": "Добавить",
"editProperty": "Редактировать свойство"
},
"row": {
"duplicate": "Дублировать",
"delete": "Удалить",
"textPlaceholder": "Пусто",
"copyProperty": "Свойство скопировано"
},
"selectOption": {
"create": "Создать",
"purpleColor": "Фиолетовый",
"pinkColor": "Розовый",
"lightPinkColor": "Светло-розовый",
"orangeColor": "Оранжевый",
"yellowColor": "Желтый",
"limeColor": "Ярко-зелёный",
"greenColor": "Зелёный",
"aquaColor": "Морской волны",
"blueColor": "Синий",
"deleteTag": "Удалить вариант",
"colorPanelTitle": "Цвета",
"panelTitle": "Выберите или создайте вариант",
"searchOption": "Поиск"
},
"date": {
"timeHintTextInTwelveHour": "12:00 AM",
"timeHintTextInTwentyFourHour": "12:00"
}
},
"sideBar": {
"openSidebar": "Open sidebar",
"closeSidebar": "Close sidebar"
}
}

View File

@ -206,8 +206,8 @@
"aquaColor": "水蓝色",
"blueColor": "蓝色",
"deleteTag": "删除标签",
"colorPannelTitle": "颜色",
"pannelTitle": "选择或新建一个标签",
"colorPanelTitle": "颜色",
"panelTitle": "选择或新建一个标签",
"searchOption": "搜索标签"
},
"menuName": "网格"

View File

@ -202,8 +202,8 @@
"aquaColor": "水藍色",
"blueColor": "藍色",
"deleteTag": "刪除標籤",
"colorPannelTitle": "顏色",
"pannelTitle": "搜尋或建立選項",
"colorPanelTitle": "顏色",
"panelTitle": "搜尋或建立選項",
"searchOption": "搜尋選項"
},
"menuName": "網格"

View File

@ -87,7 +87,7 @@ class _BoardSelectOptionCellState extends State<BoardSelectOptionCell> {
SelectOptionCellEditor.editorPanelWidth,
300,
));
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popover,
constraints: constraints,
direction: PopoverDirection.bottomWithLeftAligned,

View File

@ -1,15 +1,17 @@
import 'package:app_flowy/plugins/board/application/card/card_bloc.dart';
import 'package:app_flowy/plugins/board/application/card/card_data_controller.dart';
import 'package:app_flowy/plugins/grid/presentation/widgets/row/row_action_sheet.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
import 'board_cell.dart';
import 'card_cell_builder.dart';
import 'card_container.dart';
import 'container/accessory.dart';
import 'container/card_container.dart';
class BoardCard extends StatefulWidget {
final String gridId;
@ -38,6 +40,8 @@ class BoardCard extends StatefulWidget {
class _BoardCardState extends State<BoardCard> {
late BoardCardBloc _cardBloc;
late EditableRowNotifier rowNotifier;
late PopoverController popoverController;
AccessoryType? accessoryType;
@override
void initState() {
@ -54,6 +58,7 @@ class _BoardCardState extends State<BoardCard> {
_cardBloc.add(BoardCardEvent.setIsEditing(rowNotifier.isEditing.value));
});
popoverController = PopoverController();
super.initState();
}
@ -64,32 +69,42 @@ class _BoardCardState extends State<BoardCard> {
child: BlocBuilder<BoardCardBloc, BoardCardState>(
buildWhen: (previous, current) {
// Rebuild when:
// 1.If the lenght of the cells is not the same
// 1.If the length of the cells is not the same
// 2.isEditing changed
if (previous.cells.length != current.cells.length ||
previous.isEditing != current.isEditing) {
return true;
}
// 3.Compare the content of the cells. The cells consisits of
// 3.Compare the content of the cells. The cells consists of
// list of [BoardCellEquatable] that extends the [Equatable].
return !listEquals(previous.cells, current.cells);
},
builder: (context, state) {
return BoardCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
return [
_CardEditOption(rowNotifier: rowNotifier),
const _CardMoreOption(),
];
},
onTap: (context) => widget.openCard(context),
child: _CellColumn(
groupId: widget.groupId,
rowNotifier: rowNotifier,
cellBuilder: widget.cellBuilder,
cells: state.cells,
return AppFlowyPopover(
controller: popoverController,
constraints: BoxConstraints.loose(const Size(140, 200)),
direction: PopoverDirection.rightWithCenterAligned,
popupBuilder: (popoverContext) => _handlePopoverBuilder(
context,
popoverContext,
),
child: BoardCardContainer(
buildAccessoryWhen: () => state.isEditing == false,
accessoryBuilder: (context) {
return [
_CardEditOption(rowNotifier: rowNotifier),
_CardMoreOption(),
];
},
openAccessory: _handleOpenAccessory,
openCard: (context) => widget.openCard(context),
child: _CellColumn(
groupId: widget.groupId,
rowNotifier: rowNotifier,
cellBuilder: widget.cellBuilder,
cells: state.cells,
),
),
);
},
@ -97,6 +112,30 @@ class _BoardCardState extends State<BoardCard> {
);
}
void _handleOpenAccessory(AccessoryType newAccessoryType) {
accessoryType = newAccessoryType;
switch (newAccessoryType) {
case AccessoryType.edit:
break;
case AccessoryType.more:
popoverController.show();
break;
}
}
Widget _handlePopoverBuilder(
BuildContext context,
BuildContext popoverContext,
) {
switch (accessoryType!) {
case AccessoryType.edit:
throw UnimplementedError();
case AccessoryType.more:
return GridRowActionSheet(
rowData: context.read<BoardCardBloc>().rowInfo());
}
}
@override
Future<void> dispose() async {
rowNotifier.dispose();
@ -163,7 +202,7 @@ class _CellColumn extends StatelessWidget {
}
class _CardMoreOption extends StatelessWidget with CardAccessory {
const _CardMoreOption({Key? key}) : super(key: key);
_CardMoreOption({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -175,11 +214,7 @@ class _CardMoreOption extends StatelessWidget with CardAccessory {
}
@override
void onTap(BuildContext context) {
GridRowActionSheet(
rowData: context.read<BoardCardBloc>().rowInfo(),
).show(context, direction: AnchorDirection.bottomWithCenterAligned);
}
AccessoryType get type => AccessoryType.more;
}
class _CardEditOption extends StatelessWidget with CardAccessory {
@ -201,7 +236,8 @@ class _CardEditOption extends StatelessWidget with CardAccessory {
}
@override
void onTap(BuildContext context) {
rowNotifier.becomeFirstResponder();
}
void onTap(BuildContext context) => rowNotifier.becomeFirstResponder();
@override
AccessoryType get type => AccessoryType.edit;
}

View File

@ -0,0 +1,74 @@
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart';
enum AccessoryType {
edit,
more,
}
abstract class CardAccessory implements Widget {
AccessoryType get type;
void onTap(BuildContext context) {}
}
typedef CardAccessoryBuilder = List<CardAccessory> Function(
BuildContext buildContext,
);
class CardAccessoryContainer extends StatelessWidget {
final void Function(AccessoryType) onTapAccessory;
final List<CardAccessory> accessories;
const CardAccessoryContainer({
required this.accessories,
required this.onTapAccessory,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
final children = accessories.map((accessory) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () {
accessory.onTap(context);
onTapAccessory(accessory.type);
},
child: _wrapHover(theme, accessory),
);
}).toList();
return _wrapDecoration(context, Row(children: children));
}
FlowyHover _wrapHover(AppTheme theme, CardAccessory accessory) {
return FlowyHover(
style: HoverStyle(
hoverColor: theme.hover,
backgroundColor: theme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
width: 24,
height: 24,
child: accessory,
),
);
}
Widget _wrapDecoration(BuildContext context, Widget child) {
final theme = context.read<AppTheme>();
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
final decoration = BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
borderRadius: const BorderRadius.all(Radius.circular(4)),
);
return Container(
clipBehavior: Clip.hardEdge,
decoration: decoration,
child: child,
);
}
}

View File

@ -1,17 +1,19 @@
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'accessory.dart';
class BoardCardContainer extends StatelessWidget {
final Widget child;
final CardAccessoryBuilder? accessoryBuilder;
final bool Function()? buildAccessoryWhen;
final void Function(BuildContext) onTap;
final void Function(BuildContext) openCard;
final void Function(AccessoryType) openAccessory;
const BoardCardContainer({
required this.child,
required this.onTap,
required this.openCard,
required this.openAccessory,
this.accessoryBuilder,
this.buildAccessoryWhen,
Key? key,
@ -34,13 +36,14 @@ class BoardCardContainer extends StatelessWidget {
if (accessories.isNotEmpty) {
container = _CardEnterRegion(
accessories: accessories,
onTapAccessory: openAccessory,
child: container,
);
}
}
return GestureDetector(
onTap: () => onTap(context),
onTap: () => openCard(context),
child: Padding(
padding: const EdgeInsets.all(8),
child: ConstrainedBox(
@ -55,69 +58,16 @@ class BoardCardContainer extends StatelessWidget {
}
}
abstract class CardAccessory implements Widget {
void onTap(BuildContext context);
}
typedef CardAccessoryBuilder = List<CardAccessory> Function(
BuildContext buildContext,
);
class CardAccessoryContainer extends StatelessWidget {
final List<CardAccessory> accessories;
const CardAccessoryContainer({required this.accessories, Key? key})
: super(key: key);
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
final children = accessories.map((accessory) {
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => accessory.onTap(context),
child: _wrapHover(theme, accessory),
);
}).toList();
return _wrapDecoration(context, Row(children: children));
}
FlowyHover _wrapHover(AppTheme theme, CardAccessory accessory) {
return FlowyHover(
style: HoverStyle(
hoverColor: theme.hover,
backgroundColor: theme.surface,
borderRadius: BorderRadius.zero,
),
builder: (_, onHover) => SizedBox(
width: 24,
height: 24,
child: accessory,
),
);
}
Widget _wrapDecoration(BuildContext context, Widget child) {
final theme = context.read<AppTheme>();
final borderSide = BorderSide(color: theme.shader6, width: 1.0);
final decoration = BoxDecoration(
color: Colors.transparent,
border: Border.fromBorderSide(borderSide),
borderRadius: const BorderRadius.all(Radius.circular(4)),
);
return Container(
clipBehavior: Clip.hardEdge,
decoration: decoration,
child: child,
);
}
}
class _CardEnterRegion extends StatelessWidget {
final Widget child;
final List<CardAccessory> accessories;
const _CardEnterRegion(
{required this.child, required this.accessories, Key? key})
: super(key: key);
final void Function(AccessoryType) onTapAccessory;
const _CardEnterRegion({
required this.child,
required this.accessories,
required this.onTapAccessory,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -126,9 +76,12 @@ class _CardEnterRegion extends StatelessWidget {
builder: (context, onEnter, _) {
List<Widget> children = [child];
if (onEnter) {
children.add(CardAccessoryContainer(
accessories: accessories,
).positioned(right: 0));
children.add(
CardAccessoryContainer(
accessories: accessories,
onTapAccessory: onTapAccessory,
).positioned(right: 0),
);
}
return MouseRegion(

View File

@ -50,7 +50,6 @@ class BoardSettingList extends StatelessWidget {
previous.selectedAction != current.selectedAction,
listener: (context, state) {
state.selectedAction.foldLeft(null, (_, action) {
// FlowyOverlay.of(context).remove(identifier());
onAction(action, settingContext);
});
},

View File

@ -62,7 +62,7 @@ class _SettingButtonState extends State<_SettingButton> {
@override
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: popoverController,
constraints: BoxConstraints.loose(const Size(260, 400)),
triggerActions: PopoverTriggerActionFlags.click,

View File

@ -63,7 +63,7 @@ class _DateCellState extends GridCellState<GridDateCell> {
value: _cellBloc,
child: BlocBuilder<DateCellBloc, DateCellState>(
builder: (context, state) {
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popover,
offset: const Offset(0, 20),
direction: PopoverDirection.bottomWithLeftAligned,

View File

@ -299,7 +299,7 @@ class _DateTypeOptionButton extends StatelessWidget {
return BlocSelector<DateCalBloc, DateCalState, DateTypeOptionPB>(
selector: (state) => state.dateTypeOptionPB,
builder: (context, dateTypeOptionPB) {
return AppFlowyStylePopover(
return AppFlowyPopover(
triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
offset: const Offset(20, 0),

View File

@ -181,7 +181,7 @@ class _SelectOptionWrapState extends State<SelectOptionWrap> {
SelectOptionCellEditor.editorPanelWidth,
300,
));
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popover,
constraints: constraints,
direction: PopoverDirection.bottomWithLeftAligned,

View File

@ -25,31 +25,47 @@ import 'text_field.dart';
const double _editorPanelWidth = 300;
class SelectOptionCellEditor extends StatelessWidget {
class SelectOptionCellEditor extends StatefulWidget {
final GridSelectOptionCellController cellController;
static double editorPanelWidth = 300;
const SelectOptionCellEditor({required this.cellController, Key? key})
: super(key: key);
@override
State<SelectOptionCellEditor> createState() => _SelectOptionCellEditorState();
}
class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
late PopoverMutex popoverMutex;
@override
void initState() {
popoverMutex = PopoverMutex();
super.initState();
}
@override
Widget build(BuildContext context) {
return BlocProvider(
create: (context) => SelectOptionCellEditorBloc(
cellController: cellController,
cellController: widget.cellController,
)..add(const SelectOptionEditorEvent.initial()),
child: BlocBuilder<SelectOptionCellEditorBloc, SelectOptionEditorState>(
builder: (context, state) {
return CustomScrollView(
shrinkWrap: true,
slivers: [
SliverToBoxAdapter(child: _TextField()),
SliverToBoxAdapter(
child: _TextField(popoverMutex: popoverMutex),
),
const SliverToBoxAdapter(child: VSpace(6)),
const SliverToBoxAdapter(child: TypeOptionSeparator()),
const SliverToBoxAdapter(child: VSpace(6)),
const SliverToBoxAdapter(child: _Title()),
const SliverToBoxAdapter(child: _OptionList()),
SliverToBoxAdapter(
child: _OptionList(popoverMutex: popoverMutex),
),
],
);
},
@ -59,7 +75,11 @@ class SelectOptionCellEditor extends StatelessWidget {
}
class _OptionList extends StatelessWidget {
const _OptionList({Key? key}) : super(key: key);
final PopoverMutex popoverMutex;
const _OptionList({
required this.popoverMutex,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -68,7 +88,10 @@ class _OptionList extends StatelessWidget {
List<Widget> cells = [];
cells.addAll(state.options.map((option) {
return _SelectOptionCell(
option, state.selectedOptions.contains(option));
option: option,
isSelected: state.selectedOptions.contains(option),
popoverMutex: popoverMutex,
);
}).toList());
state.createOption.fold(
@ -101,9 +124,13 @@ class _OptionList extends StatelessWidget {
}
class _TextField extends StatelessWidget {
final PopoverMutex popoverMutex;
final TextfieldTagsController _tagController = TextfieldTagsController();
_TextField({Key? key}) : super(key: key);
_TextField({
required this.popoverMutex,
Key? key,
}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -121,8 +148,7 @@ class _TextField extends StatelessWidget {
selectedOptionMap: optionMap,
distanceToText: _editorPanelWidth * 0.7,
tagController: _tagController,
onClick: () => FlowyOverlay.of(context)
.remove(SelectOptionTypeOptionEditor.identifier),
onClick: () => popoverMutex.close(),
newText: (text) {
context
.read<SelectOptionCellEditorBloc>()
@ -151,7 +177,7 @@ class _Title extends StatelessWidget {
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 6),
child: FlowyText.medium(
LocaleKeys.grid_selectOption_pannelTitle.tr(),
LocaleKeys.grid_selectOption_panelTitle.tr(),
fontSize: 12,
color: theme.shader3,
),
@ -189,9 +215,14 @@ class _CreateOptionCell extends StatelessWidget {
class _SelectOptionCell extends StatefulWidget {
final SelectOptionPB option;
final PopoverMutex popoverMutex;
final bool isSelected;
const _SelectOptionCell(this.option, this.isSelected, {Key? key})
: super(key: key);
const _SelectOptionCell({
required this.option,
required this.isSelected,
required this.popoverMutex,
Key? key,
}) : super(key: key);
@override
State<_SelectOptionCell> createState() => _SelectOptionCellState();
@ -209,10 +240,11 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popoverController,
offset: const Offset(20, 0),
constraints: BoxConstraints.loose(const Size(200, 300)),
mutex: widget.popoverMutex,
child: SizedBox(
height: GridSize.typeOptionItemHeight,
child: Row(
@ -257,8 +289,9 @@ class _SelectOptionCellState extends State<_SelectOptionCell> {
.read<SelectOptionCellEditorBloc>()
.add(SelectOptionEditorEvent.updateOption(updatedOption));
},
key: ValueKey(widget.option
.id), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
key: ValueKey(
widget.option.id,
), // Use ValueKey to refresh the UI, otherwise, it will remain the old value.
);
},
);

View File

@ -130,7 +130,7 @@ class _GridURLCellState extends GridCellState<GridURLCell> {
),
);
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popoverController,
constraints: BoxConstraints.loose(const Size(300, 160)),
direction: PopoverDirection.bottomWithLeftAligned,
@ -216,7 +216,7 @@ class _EditURLAccessoryState extends State<_EditURLAccessory>
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
constraints: BoxConstraints.loose(const Size(300, 160)),
controller: _popoverController,
direction: PopoverDirection.bottomWithLeftAligned,

View File

@ -30,7 +30,7 @@ class GridFieldCell extends StatelessWidget {
},
child: BlocBuilder<FieldCellBloc, FieldCellState>(
builder: (context, state) {
final button = AppFlowyStylePopover(
final button = AppFlowyPopover(
constraints: BoxConstraints.loose(const Size(240, 840)),
direction: PopoverDirection.bottomWithLeftAligned,
triggerActions: PopoverTriggerActionFlags.click,

View File

@ -167,7 +167,7 @@ class _FieldNameTextFieldState extends State<_FieldNameTextField> {
},
child: BlocBuilder<FieldEditorBloc, FieldEditorState>(
builder: (context, state) {
listenOnPopoverChhanged(context);
listenOnPopoverChanged(context);
return RoundedInputField(
height: 36,
@ -191,7 +191,7 @@ class _FieldNameTextFieldState extends State<_FieldNameTextField> {
);
}
void listenOnPopoverChhanged(BuildContext context) {
void listenOnPopoverChanged(BuildContext context) {
if (_popoverCallback != null) {
widget.popoverMutex.removePopoverStateListener(_popoverCallback!);
}
@ -243,7 +243,7 @@ class _DeleteFieldButton extends StatelessWidget {
}
Widget _wrapPopover(Widget widget) {
return AppFlowyStylePopover(
return AppFlowyPopover(
triggerActions: PopoverTriggerActionFlags.click,
constraints: BoxConstraints.loose(const Size(400, 240)),
mutex: popoverMutex,

View File

@ -64,7 +64,7 @@ class FieldTypeOptionEditor extends StatelessWidget {
final theme = context.watch<AppTheme>();
return SizedBox(
height: GridSize.typeOptionItemHeight,
child: AppFlowyStylePopover(
child: AppFlowyPopover(
constraints: BoxConstraints.loose(const Size(460, 440)),
triggerActions:
PopoverTriggerActionFlags.click | PopoverTriggerActionFlags.hover,

View File

@ -176,7 +176,7 @@ class CreateFieldButton extends StatelessWidget {
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
triggerActions: PopoverTriggerActionFlags.click,
direction: PopoverDirection.bottomWithRightAligned,
constraints: BoxConstraints.loose(const Size(240, 200)),

View File

@ -62,7 +62,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
}
Widget _renderDateFormatButton(BuildContext context, DateFormat dataFormat) {
return AppFlowyStylePopover(
return AppFlowyPopover(
mutex: popoverMutex,
triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,
@ -84,7 +84,7 @@ class DateTypeOptionWidget extends TypeOptionWidget {
}
Widget _renderTimeFormatButton(BuildContext context, TimeFormat timeFormat) {
return AppFlowyStylePopover(
return AppFlowyPopover(
mutex: popoverMutex,
triggerActions:
PopoverTriggerActionFlags.hover | PopoverTriggerActionFlags.click,

View File

@ -55,7 +55,7 @@ class NumberTypeOptionWidget extends TypeOptionWidget {
listener: (context, state) =>
typeOptionContext.typeOption = state.typeOption,
builder: (context, state) {
return AppFlowyStylePopover(
return AppFlowyPopover(
mutex: popoverMutex,
triggerActions: PopoverTriggerActionFlags.hover |
PopoverTriggerActionFlags.click,

View File

@ -180,7 +180,7 @@ class _OptionCellState extends State<_OptionCell> {
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
controller: _popoverController,
mutex: widget.popoverMutex,
offset: const Offset(20, 0),

View File

@ -139,7 +139,7 @@ class SelectOptionColorList extends StatelessWidget {
child: SizedBox(
height: GridSize.typeOptionItemHeight,
child: FlowyText.medium(
LocaleKeys.grid_selectOption_colorPannelTitle.tr(),
LocaleKeys.grid_selectOption_colorPanelTitle.tr(),
fontSize: 12,
textAlign: TextAlign.left,
),

View File

@ -1,8 +1,10 @@
import 'package:app_flowy/plugins/grid/application/prelude.dart';
import 'package:app_flowy/plugins/grid/application/row/row_cache.dart';
import 'package:app_flowy/plugins/grid/application/row/row_data_controller.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/icon_button.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
@ -56,20 +58,21 @@ class _GridRowWidgetState extends State<GridRowWidget> {
child: BlocBuilder<RowBloc, RowState>(
buildWhen: (p, c) => p.rowInfo.rowPB.height != c.rowInfo.rowPB.height,
builder: (context, state) {
final children = [
const _RowLeading(),
Expanded(
child: RowContent(
builder: widget.cellBuilder,
onExpand: () => widget.openDetailPage(
context,
widget.cellBuilder,
),
final content = Expanded(
child: RowContent(
builder: widget.cellBuilder,
onExpand: () => widget.openDetailPage(
context,
widget.cellBuilder,
),
),
);
return Row(children: [
const _RowLeading(),
content,
const _RowTrailing(),
];
return Row(children: children);
]);
},
),
),
@ -83,26 +86,51 @@ class _GridRowWidgetState extends State<GridRowWidget> {
}
}
class _RowLeading extends StatelessWidget {
class _RowLeading extends StatefulWidget {
const _RowLeading({Key? key}) : super(key: key);
@override
State<_RowLeading> createState() => _RowLeadingState();
}
class _RowLeadingState extends State<_RowLeading> {
late PopoverController popoverController;
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override
Widget build(BuildContext context) {
return Consumer<RegionStateNotifier>(
builder: (context, state, _) {
return SizedBox(
width: GridSize.leadingHeaderPadding,
child: state.onEnter ? _activeWidget() : null);
return AppFlowyPopover(
controller: popoverController,
constraints: BoxConstraints.loose(const Size(140, 200)),
direction: PopoverDirection.rightWithCenterAligned,
popupBuilder: (BuildContext popoverContext) {
return GridRowActionSheet(
rowData: context.read<RowBloc>().state.rowInfo);
},
child: Consumer<RegionStateNotifier>(
builder: (context, state, _) {
return SizedBox(
width: GridSize.leadingHeaderPadding,
child: state.onEnter ? _activeWidget() : null,
);
},
),
);
}
Widget _activeWidget() {
return Row(
mainAxisAlignment: MainAxisAlignment.center,
children: const [
_InsertRowButton(),
_DeleteRowButton(),
children: [
const _InsertButton(),
_MenuButton(openMenu: () {
popoverController.show();
}),
],
);
}
@ -117,8 +145,8 @@ class _RowTrailing extends StatelessWidget {
}
}
class _InsertRowButton extends StatelessWidget {
const _InsertRowButton({Key? key}) : super(key: key);
class _InsertButton extends StatelessWidget {
const _InsertButton({Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -128,17 +156,29 @@ class _InsertRowButton extends StatelessWidget {
hoverColor: theme.hover,
width: 20,
height: 30,
onPressed: () => context.read<RowBloc>().add(
const RowEvent.createRow(),
),
onPressed: () => context.read<RowBloc>().add(const RowEvent.createRow()),
iconPadding: const EdgeInsets.all(3),
icon: svgWidget("home/add"),
);
}
}
class _DeleteRowButton extends StatelessWidget {
const _DeleteRowButton({Key? key}) : super(key: key);
class _MenuButton extends StatefulWidget {
final VoidCallback openMenu;
const _MenuButton({
required this.openMenu,
Key? key,
}) : super(key: key);
@override
State<_MenuButton> createState() => _MenuButtonState();
}
class _MenuButtonState extends State<_MenuButton> {
@override
void initState() {
super.initState();
}
@override
Widget build(BuildContext context) {
@ -148,9 +188,7 @@ class _DeleteRowButton extends StatelessWidget {
hoverColor: theme.hover,
width: 20,
height: 30,
onPressed: () => GridRowActionSheet(
rowData: context.read<RowBloc>().state.rowInfo,
).show(context),
onPressed: () => widget.openMenu(),
iconPadding: const EdgeInsets.all(3),
icon: svgWidget("editor/details"),
);

View File

@ -3,7 +3,6 @@ import 'package:easy_localization/easy_localization.dart';
import 'package:app_flowy/generated/locale_keys.g.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
@ -27,10 +26,7 @@ class GridRowActionSheet extends StatelessWidget {
final cells = _RowAction.values
.where((value) => value.enable())
.map(
(action) => _RowActionCell(
action: action,
onDismissed: () => remove(context),
),
(action) => _RowActionCell(action: action),
)
.toList();
@ -52,37 +48,11 @@ class GridRowActionSheet extends StatelessWidget {
),
);
}
void show(
BuildContext overlayContext, {
AnchorDirection direction = AnchorDirection.leftWithCenterAligned,
}) {
FlowyOverlay.of(overlayContext).insertWithAnchor(
widget: OverlayContainer(
constraints: BoxConstraints.loose(const Size(140, 200)),
child: this,
),
identifier: GridRowActionSheet.identifier(),
anchorContext: overlayContext,
anchorDirection: direction,
);
}
void remove(BuildContext overlayContext) {
FlowyOverlay.of(overlayContext).remove(GridRowActionSheet.identifier());
}
static String identifier() {
return (GridRowActionSheet).toString();
}
}
class _RowActionCell extends StatelessWidget {
final _RowAction action;
final VoidCallback onDismissed;
const _RowActionCell(
{required this.action, required this.onDismissed, Key? key})
: super(key: key);
const _RowActionCell({required this.action, Key? key}) : super(key: key);
@override
Widget build(BuildContext context) {
@ -101,7 +71,6 @@ class _RowActionCell extends StatelessWidget {
if (action.enable()) {
action.performAction(context);
}
onDismissed();
},
leftIcon: svgWidget(action.iconName(), color: theme.iconColor),
),

View File

@ -194,7 +194,7 @@ class _CreateFieldButtonState extends State<_CreateFieldButton> {
Widget build(BuildContext context) {
final theme = context.read<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
constraints: BoxConstraints.loose(const Size(240, 200)),
controller: popoverController,
triggerActions: PopoverTriggerActionFlags.click,

View File

@ -99,7 +99,6 @@ class _GridGroupCell extends StatelessWidget {
),
);
onSelected();
// FlowyOverlay.of(context).remove(GridGroupList.identifier());
},
),
);

View File

@ -116,7 +116,7 @@ class _GridPropertyCell extends StatelessWidget {
}
Widget _editFieldButton(AppTheme theme, BuildContext context) {
return AppFlowyStylePopover(
return AppFlowyPopover(
mutex: popoverMutex,
triggerActions: PopoverTriggerActionFlags.click,
offset: const Offset(20, 0),

View File

@ -2,7 +2,6 @@ import 'package:app_flowy/plugins/grid/application/setting/setting_bloc.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra/image.dart';
import 'package:flowy_infra/theme.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/button.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart';
@ -40,7 +39,6 @@ class GridSettingList extends StatelessWidget {
previous.selectedAction != current.selectedAction,
listener: (context, state) {
state.selectedAction.foldLeft(null, (_, action) {
FlowyOverlay.of(context).remove(identifier());
onAction(action, settingContext);
});
},

View File

@ -53,7 +53,7 @@ class _SettingButton extends StatelessWidget {
@override
Widget build(BuildContext context) {
final theme = context.watch<AppTheme>();
return AppFlowyStylePopover(
return AppFlowyPopover(
constraints: BoxConstraints.loose(const Size(260, 400)),
triggerActions: PopoverTriggerActionFlags.click,
offset: const Offset(0, 10),

View File

@ -1,63 +0,0 @@
import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/widget/rounded_input_field.dart';
import 'package:flutter/material.dart';
import 'package:window_size/window_size.dart';
class FlowyPoppuWindow extends StatelessWidget {
final Widget child;
const FlowyPoppuWindow({Key? key, required this.child}) : super(key: key);
@override
Widget build(BuildContext context) {
return Material(
type: MaterialType.transparency,
child: child,
);
}
static Future<void> show(
BuildContext context, {
required Widget child,
required Size size,
}) async {
final window = await getWindowInfo();
// ignore: use_build_context_synchronously
FlowyOverlay.of(context).insertWithRect(
widget: FlowyPoppuWindow(child: child),
identifier: 'FlowyPoppuWindow',
anchorPosition: Offset(-size.width / 2.0, -size.height / 2.0),
anchorSize: window.frame.size,
anchorDirection: AnchorDirection.center,
style: FlowyOverlayStyle(blur: false),
);
}
}
class PopupTextField extends StatelessWidget {
final void Function(String) textDidChange;
const PopupTextField({
Key? key,
required this.textDidChange,
}) : super(key: key);
@override
Widget build(BuildContext context) {
return RoundedInputField(
style: const TextStyle(fontSize: 14, fontWeight: FontWeight.w500),
hintText: '',
normalBorderColor: const Color(0xffbdbdbd),
onChanged: textDidChange,
);
}
static void show(
{required BuildContext context,
required Size size,
required void Function(String) textDidChange}) {
FlowyPoppuWindow.show(
context,
size: size,
child: PopupTextField(textDidChange: textDidChange),
);
}
}

View File

@ -6,11 +6,11 @@ import 'package:flutter/services.dart';
/// If multiple popovers are exclusive,
/// pass the same mutex to them.
class PopoverMutex {
final ValueNotifier<PopoverState?> _stateNofitier = ValueNotifier(null);
final ValueNotifier<PopoverState?> _stateNotifier = ValueNotifier(null);
PopoverMutex();
void removePopoverStateListener(VoidCallback listener) {
_stateNofitier.removeListener(listener);
_stateNotifier.removeListener(listener);
}
VoidCallback listenOnPopoverStateChanged(VoidCallback callback) {
@ -18,29 +18,29 @@ class PopoverMutex {
callback();
}
_stateNofitier.addListener(listenerCallback);
_stateNotifier.addListener(listenerCallback);
return listenerCallback;
}
void close() {
_stateNofitier.value?.close();
_stateNotifier.value?.close();
}
PopoverState? get state => _stateNofitier.value;
PopoverState? get state => _stateNotifier.value;
set state(PopoverState? newState) {
if (_stateNofitier.value != null && _stateNofitier.value != newState) {
_stateNofitier.value?.close();
if (_stateNotifier.value != null && _stateNotifier.value != newState) {
_stateNotifier.value?.close();
}
_stateNofitier.value = newState;
_stateNotifier.value = newState;
}
void _removeState() {
_stateNofitier.value = null;
_stateNotifier.value = null;
}
void dispose() {
_stateNofitier.dispose();
_stateNotifier.dispose();
}
}

View File

@ -2,7 +2,7 @@ import 'package:flowy_infra_ui/flowy_infra_ui_web.dart';
import 'package:appflowy_popover/popover.dart';
import 'package:flutter/material.dart';
class AppFlowyStylePopover extends StatelessWidget {
class AppFlowyPopover extends StatelessWidget {
final Widget child;
final PopoverController? controller;
final Widget Function(BuildContext context) popupBuilder;
@ -13,7 +13,7 @@ class AppFlowyStylePopover extends StatelessWidget {
final PopoverMutex? mutex;
final Offset? offset;
const AppFlowyStylePopover({
const AppFlowyPopover({
Key? key,
required this.child,
required this.popupBuilder,