fix: billing+cleanup (#5634)

* fix: billing fixes

* chore: best practice and cleaning

* chore: dispose of unused resources

* chore: upgrade editor version
This commit is contained in:
Mathias Mogensen 2024-06-27 02:00:21 +02:00 committed by GitHub
parent 7859fc7922
commit bbb3f95a13
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
49 changed files with 392 additions and 316 deletions

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/ai_chat/chat_page.dart'; import 'package:appflowy/plugins/ai_chat/chat_page.dart';
import 'package:appflowy/plugins/util.dart'; import 'package:appflowy/plugins/util.dart';
@ -7,7 +9,6 @@ import 'package:appflowy/workspace/presentation/home/home_stack.dart';
import 'package:appflowy/workspace/presentation/widgets/tab_bar_item.dart'; import 'package:appflowy/workspace/presentation/widgets/tab_bar_item.dart';
import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart'; import 'package:appflowy/workspace/presentation/widgets/view_title_bar.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class AIChatPluginBuilder extends PluginBuilder { class AIChatPluginBuilder extends PluginBuilder {
@ -65,6 +66,13 @@ class AIChatPagePlugin extends Plugin {
_viewInfoBloc = ViewInfoBloc(view: notifier.view) _viewInfoBloc = ViewInfoBloc(view: notifier.view)
..add(const ViewInfoEvent.started()); ..add(const ViewInfoEvent.started());
} }
@override
void dispose() {
_viewInfoBloc.close();
notifier.dispose();
super.dispose();
}
} }
class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder class AIChatPagePluginWidgetBuilder extends PluginWidgetBuilder

View File

@ -1,9 +1,10 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker_header.dart'; import 'package:appflowy/plugins/base/emoji/emoji_picker_header.dart';
import 'package:appflowy/plugins/base/emoji/emoji_search_bar.dart'; import 'package:appflowy/plugins/base/emoji/emoji_search_bar.dart';
import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart'; import 'package:appflowy/plugins/base/emoji/emoji_skin_tone.dart';
import 'package:flowy_infra/size.dart'; import 'package:flowy_infra/size.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_emoji_mart/flutter_emoji_mart.dart'; import 'package:flutter_emoji_mart/flutter_emoji_mart.dart';
// use a global value to store the selected emoji to prevent reloading every time. // use a global value to store the selected emoji to prevent reloading every time.
@ -37,9 +38,7 @@ class _FlowyEmojiPickerState extends State<FlowyEmojiPicker> {
EmojiData.builtIn().then( EmojiData.builtIn().then(
(value) { (value) {
kCachedEmojiData = value; kCachedEmojiData = value;
setState(() { setState(() => emojiData = value);
emojiData = value;
});
}, },
); );
} }

View File

@ -1,5 +1,7 @@
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart'; import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/application/view/view_cache.dart'; import 'package:appflowy/plugins/database/application/view/view_cache.dart';
import 'package:appflowy/plugins/database/domain/database_view_service.dart'; import 'package:appflowy/plugins/database/domain/database_view_service.dart';
@ -12,7 +14,6 @@ import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_result/appflowy_result.dart'; import 'package:appflowy_result/appflowy_result.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'defines.dart'; import 'defines.dart';
import 'row/row_cache.dart'; import 'row/row_cache.dart';
@ -223,6 +224,7 @@ class DatabaseController {
_databaseCallbacks.clear(); _databaseCallbacks.clear();
_groupCallbacks.clear(); _groupCallbacks.clear();
_layoutCallbacks.clear(); _layoutCallbacks.clear();
_isLoading.dispose();
} }
Future<void> _loadGroups() async { Future<void> _loadGroups() async {

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/mobile/presentation/bottom_sheet/bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/bottom_sheet.dart';
@ -19,12 +21,12 @@ 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:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'package:go_router/go_router.dart'; import 'package:go_router/go_router.dart';
import '../../application/row/row_controller.dart'; import '../../application/row/row_controller.dart';
import '../../widgets/row/row_detail.dart'; import '../../widgets/row/row_detail.dart';
import 'calendar_day.dart'; import 'calendar_day.dart';
import 'layout/sizes.dart'; import 'layout/sizes.dart';
import 'toolbar/calendar_setting_bar.dart'; import 'toolbar/calendar_setting_bar.dart';
@ -90,12 +92,11 @@ class _CalendarPageState extends State<CalendarPage> {
@override @override
void initState() { void initState() {
super.initState();
_calendarState = GlobalKey<MonthViewState>(); _calendarState = GlobalKey<MonthViewState>();
_calendarBloc = CalendarBloc( _calendarBloc = CalendarBloc(
databaseController: widget.databaseController, databaseController: widget.databaseController,
)..add(const CalendarEvent.initial()); )..add(const CalendarEvent.initial());
super.initState();
} }
@override @override
@ -378,13 +379,7 @@ class UnscheduledEventsButton extends StatefulWidget {
} }
class _UnscheduledEventsButtonState extends State<UnscheduledEventsButton> { class _UnscheduledEventsButtonState extends State<UnscheduledEventsButton> {
late final PopoverController _popoverController; final PopoverController _popoverController = PopoverController();
@override
void initState() {
super.initState();
_popoverController = PopoverController();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -30,6 +30,12 @@ class CalendarLayoutSetting extends StatefulWidget {
class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> { class _CalendarLayoutSettingState extends State<CalendarLayoutSetting> {
final PopoverMutex popoverMutex = PopoverMutex(); final PopoverMutex popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider( return BlocProvider(

View File

@ -1,18 +1,19 @@
import 'package:flutter/material.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/grid/application/filter/checkbox_filter_editor_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/checkbox_filter_editor_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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:appflowy_backend/protobuf/flowy-database2/checkbox_filter.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../condition_button.dart'; import '../condition_button.dart';
import '../disclosure_button.dart'; import '../disclosure_button.dart';
import '../filter_info.dart'; import '../filter_info.dart';
import 'choicechip.dart'; import 'choicechip.dart';
class CheckboxFilterChoicechip extends StatefulWidget { class CheckboxFilterChoicechip extends StatefulWidget {
@ -30,9 +31,9 @@ class _CheckboxFilterChoicechipState extends State<CheckboxFilterChoicechip> {
@override @override
void initState() { void initState() {
super.initState();
bloc = CheckboxFilterEditorBloc(filterInfo: widget.filterInfo) bloc = CheckboxFilterEditorBloc(filterInfo: widget.filterInfo)
..add(const CheckboxFilterEditorEvent.initial()); ..add(const CheckboxFilterEditorEvent.initial());
super.initState();
} }
@override @override
@ -82,6 +83,12 @@ class CheckboxFilterEditor extends StatefulWidget {
class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> { class _CheckboxFilterEditorState extends State<CheckboxFilterEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider.value( return BlocProvider.value(

View File

@ -1,12 +1,14 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/database/grid/application/filter/checklist_filter_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/checklist_filter_bloc.dart';
import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart'; import 'package:appflowy/workspace/presentation/widgets/pop_up_action.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/checklist_filter.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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:appflowy_backend/protobuf/flowy-database2/checklist_filter.pbenum.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../condition_button.dart'; import '../../condition_button.dart';
import '../../disclosure_button.dart'; import '../../disclosure_button.dart';
import '../../filter_info.dart'; import '../../filter_info.dart';
@ -23,20 +25,20 @@ class ChecklistFilterChoicechip extends StatefulWidget {
} }
class _ChecklistFilterChoicechipState extends State<ChecklistFilterChoicechip> { class _ChecklistFilterChoicechipState extends State<ChecklistFilterChoicechip> {
late ChecklistFilterEditorBloc bloc; late final ChecklistFilterEditorBloc bloc;
late PopoverMutex popoverMutex; final PopoverMutex popoverMutex = PopoverMutex();
@override @override
void initState() { void initState() {
popoverMutex = PopoverMutex(); super.initState();
bloc = ChecklistFilterEditorBloc(filterInfo: widget.filterInfo); bloc = ChecklistFilterEditorBloc(filterInfo: widget.filterInfo);
bloc.add(const ChecklistFilterEditorEvent.initial()); bloc.add(const ChecklistFilterEditorEvent.initial());
super.initState();
} }
@override @override
void dispose() { void dispose() {
bloc.close(); bloc.close();
popoverMutex.dispose();
super.dispose(); super.dispose();
} }

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/grid/application/filter/number_filter_editor_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/number_filter_editor_bloc.dart';
@ -6,12 +8,12 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../condition_button.dart'; import '../condition_button.dart';
import '../disclosure_button.dart'; import '../disclosure_button.dart';
import '../filter_info.dart'; import '../filter_info.dart';
import 'choicechip.dart'; import 'choicechip.dart';
class NumberFilterChoiceChip extends StatefulWidget { class NumberFilterChoiceChip extends StatefulWidget {
@ -64,6 +66,12 @@ class NumberFilterEditor extends StatefulWidget {
class _NumberFilterEditorState extends State<NumberFilterEditor> { class _NumberFilterEditorState extends State<NumberFilterEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<NumberFilterEditorBloc, NumberFilterEditorState>( return BlocBuilder<NumberFilterEditorBloc, NumberFilterEditorState>(

View File

@ -1,14 +1,16 @@
import 'package:flutter/material.dart';
import 'package:appflowy/plugins/database/grid/application/filter/select_option_filter_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/select_option_filter_bloc.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/field_entities.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/select_option_filter.pb.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 '../../disclosure_button.dart'; import '../../disclosure_button.dart';
import '../../filter_info.dart'; import '../../filter_info.dart';
import '../choicechip.dart'; import '../choicechip.dart';
import 'condition_list.dart'; import 'condition_list.dart';
import 'option_list.dart'; import 'option_list.dart';
import 'select_option_loader.dart'; import 'select_option_loader.dart';
@ -29,6 +31,7 @@ class _SelectOptionFilterChoicechipState
@override @override
void initState() { void initState() {
super.initState();
if (widget.filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) { if (widget.filterInfo.fieldInfo.fieldType == FieldType.SingleSelect) {
bloc = SelectOptionFilterEditorBloc( bloc = SelectOptionFilterEditorBloc(
filterInfo: widget.filterInfo, filterInfo: widget.filterInfo,
@ -43,7 +46,6 @@ class _SelectOptionFilterChoicechipState
); );
} }
bloc.add(const SelectOptionFilterEditorEvent.initial()); bloc.add(const SelectOptionFilterEditorEvent.initial());
super.initState();
} }
@override @override
@ -90,6 +92,12 @@ class SelectOptionFilterEditor extends StatefulWidget {
class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> { class _SelectOptionFilterEditorState extends State<SelectOptionFilterEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider.value( return BlocProvider.value(

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/grid/application/filter/text_filter_editor_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/text_filter_editor_bloc.dart';
@ -6,12 +8,12 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../condition_button.dart'; import '../condition_button.dart';
import '../disclosure_button.dart'; import '../disclosure_button.dart';
import '../filter_info.dart'; import '../filter_info.dart';
import 'choicechip.dart'; import 'choicechip.dart';
class TextFilterChoicechip extends StatelessWidget { class TextFilterChoicechip extends StatelessWidget {
@ -72,6 +74,12 @@ class TextFilterEditor extends StatefulWidget {
class _TextFilterEditorState extends State<TextFilterEditor> { class _TextFilterEditorState extends State<TextFilterEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<TextFilterEditorBloc, TextFilterEditorState>( return BlocBuilder<TextFilterEditorBloc, TextFilterEditorState>(

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/grid/application/filter/time_filter_editor_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/filter/time_filter_editor_bloc.dart';
@ -6,12 +8,12 @@ import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../condition_button.dart'; import '../condition_button.dart';
import '../disclosure_button.dart'; import '../disclosure_button.dart';
import '../filter_info.dart'; import '../filter_info.dart';
import 'choicechip.dart'; import 'choicechip.dart';
class TimeFilterChoiceChip extends StatefulWidget { class TimeFilterChoiceChip extends StatefulWidget {
@ -64,6 +66,12 @@ class TimeFilterEditor extends StatefulWidget {
class _TimeFilterEditorState extends State<TimeFilterEditor> { class _TimeFilterEditorState extends State<TimeFilterEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<TimeFilterEditorBloc, TimeFilterEditorState>( return BlocBuilder<TimeFilterEditorBloc, TimeFilterEditorState>(

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/field/field_info.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart';
@ -10,7 +12,6 @@ import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/style_widget/text.dart'; import 'package:flowy_infra_ui/style_widget/text.dart';
import 'package:flowy_infra_ui/style_widget/text_field.dart'; import 'package:flowy_infra_ui/style_widget/text_field.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../../../application/field/field_controller.dart'; import '../../../../application/field/field_controller.dart';
@ -35,15 +36,15 @@ class GridCreateFilterList extends StatefulWidget {
} }
class _GridCreateFilterListState extends State<GridCreateFilterList> { class _GridCreateFilterListState extends State<GridCreateFilterList> {
late GridCreateFilterBloc editBloc; late final GridCreateFilterBloc editBloc;
@override @override
void initState() { void initState() {
super.initState();
editBloc = GridCreateFilterBloc( editBloc = GridCreateFilterBloc(
viewId: widget.viewId, viewId: widget.viewId,
fieldController: widget.fieldController, fieldController: widget.fieldController,
)..add(const GridCreateFilterEvent.initial()); )..add(const GridCreateFilterEvent.initial());
super.initState();
} }
@override @override

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/field/field_controller.dart'; import 'package:appflowy/plugins/database/application/field/field_controller.dart';
@ -5,9 +7,7 @@ import 'package:appflowy/plugins/database/grid/application/filter/filter_menu_bl
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'create_filter_list.dart'; import 'create_filter_list.dart';
@ -77,13 +77,7 @@ class AddFilterButton extends StatefulWidget {
} }
class _AddFilterButtonState extends State<AddFilterButton> { class _AddFilterButtonState extends State<AddFilterButton> {
late PopoverController popoverController; final PopoverController popoverController = PopoverController();
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/application/field/field_cell_bloc.dart'; import 'package:appflowy/plugins/database/application/field/field_cell_bloc.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart'; import 'package:appflowy/plugins/database/application/field/field_controller.dart';
@ -9,7 +11,6 @@ import 'package:appflowy_popover/appflowy_popover.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:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import '../../layout/sizes.dart'; import '../../layout/sizes.dart';
@ -41,13 +42,12 @@ class GridFieldCell extends StatefulWidget {
} }
class _GridFieldCellState extends State<GridFieldCell> { class _GridFieldCellState extends State<GridFieldCell> {
final PopoverController popoverController = PopoverController();
late final FieldCellBloc _bloc; late final FieldCellBloc _bloc;
late PopoverController popoverController;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
popoverController = PopoverController();
_bloc = FieldCellBloc(viewId: widget.viewId, fieldInfo: widget.fieldInfo); _bloc = FieldCellBloc(viewId: widget.viewId, fieldInfo: widget.fieldInfo);
if (widget.isEditing) { if (widget.isEditing) {
WidgetsBinding.instance.addPostFrameCallback((timeStamp) { WidgetsBinding.instance.addPostFrameCallback((timeStamp) {

View File

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.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/grid/application/sort/sort_editor_bloc.dart'; import 'package:appflowy/plugins/database/grid/application/sort/sort_editor_bloc.dart';
@ -7,10 +9,8 @@ import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart'; import 'package:appflowy_backend/protobuf/flowy-database2/sort_entities.pbenum.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'create_sort_list.dart'; import 'create_sort_list.dart';
@ -28,6 +28,12 @@ class SortEditor extends StatefulWidget {
class _SortEditorState extends State<SortEditor> { class _SortEditorState extends State<SortEditor> {
final popoverMutex = PopoverMutex(); final popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocBuilder<SortEditorBloc, SortEditorState>( return BlocBuilder<SortEditorBloc, SortEditorState>(

View File

@ -1,6 +1,10 @@
import 'dart:collection'; import 'dart:collection';
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
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/bloc/select_option_cell_editor_bloc.dart'; import 'package:appflowy/plugins/database/application/cell/bloc/select_option_cell_editor_bloc.dart';
@ -10,14 +14,12 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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/foundation.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 '../../grid/presentation/layout/sizes.dart'; import '../../grid/presentation/layout/sizes.dart';
import '../../grid/presentation/widgets/common/type_option_separator.dart'; import '../../grid/presentation/widgets/common/type_option_separator.dart';
import '../field/type_option_editor/select/select_option_editor.dart'; import '../field/type_option_editor/select/select_option_editor.dart';
import 'extension.dart'; import 'extension.dart';
import 'select_option_text_field.dart'; import 'select_option_text_field.dart';
@ -314,13 +316,7 @@ class _SelectOptionCell extends StatefulWidget {
} }
class _SelectOptionCellState extends State<_SelectOptionCell> { class _SelectOptionCellState extends State<_SelectOptionCell> {
late PopoverController _popoverController; final _popoverController = PopoverController();
@override
void initState() {
_popoverController = PopoverController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -370,13 +370,7 @@ class FieldDetailsEditor extends StatefulWidget {
} }
class _FieldDetailsEditorState extends State<FieldDetailsEditor> { class _FieldDetailsEditorState extends State<FieldDetailsEditor> {
late PopoverMutex popoverMutex; final PopoverMutex popoverMutex = PopoverMutex();
@override
void initState() {
popoverMutex = PopoverMutex();
super.initState();
}
@override @override
void dispose() { void dispose() {
@ -575,10 +569,7 @@ class _FieldNameTextFieldState extends State<FieldNameTextField> {
} }
class SwitchFieldButton extends StatefulWidget { class SwitchFieldButton extends StatefulWidget {
const SwitchFieldButton({ const SwitchFieldButton({super.key, required this.popoverMutex});
super.key,
required this.popoverMutex,
});
final PopoverMutex popoverMutex; final PopoverMutex popoverMutex;

View File

@ -1,5 +1,8 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.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.dart'; import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
@ -18,13 +21,12 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
import 'accessory/cell_accessory.dart';
import '../cell/editable_cell_builder.dart'; import '../cell/editable_cell_builder.dart';
import 'accessory/cell_accessory.dart';
/// Display the row properties in a list. Only used in [RowDetailPage]. /// Display the row properties in a list. Only used in [RowDetailPage].
class RowPropertyList extends StatelessWidget { class RowPropertyList extends StatelessWidget {
const RowPropertyList({ const RowPropertyList({
@ -363,15 +365,9 @@ class CreateRowFieldButton extends StatefulWidget {
} }
class _CreateRowFieldButtonState extends State<CreateRowFieldButton> { class _CreateRowFieldButtonState extends State<CreateRowFieldButton> {
late PopoverController popoverController; final PopoverController popoverController = PopoverController();
FieldPB? createdField; FieldPB? createdField;
@override
void initState() {
popoverController = PopoverController();
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return AppFlowyPopover( return AppFlowyPopover(

View File

@ -1,3 +1,5 @@
import 'package:flutter/widgets.dart';
import 'package:appflowy/plugins/database/application/database_controller.dart'; import 'package:appflowy/plugins/database/application/database_controller.dart';
import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart'; import 'package:appflowy/plugins/database/grid/presentation/layout/sizes.dart';
import 'package:appflowy/plugins/database/widgets/setting/database_setting_action.dart'; import 'package:appflowy/plugins/database/widgets/setting/database_setting_action.dart';
@ -6,7 +8,6 @@ import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart'; import 'package:flowy_infra_ui/style_widget/scrolling/styled_list.dart';
import 'package:flowy_infra_ui/widget/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
import 'package:flutter/widgets.dart';
class DatabaseSettingsList extends StatefulWidget { class DatabaseSettingsList extends StatefulWidget {
const DatabaseSettingsList({ const DatabaseSettingsList({
@ -21,7 +22,13 @@ class DatabaseSettingsList extends StatefulWidget {
} }
class _DatabaseSettingsListState extends State<DatabaseSettingsList> { class _DatabaseSettingsListState extends State<DatabaseSettingsList> {
late final PopoverMutex popoverMutex = PopoverMutex(); final PopoverMutex popoverMutex = PopoverMutex();
@override
void dispose() {
popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {

View File

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/generated/flowy_svgs.g.dart'; import 'package:appflowy/generated/flowy_svgs.g.dart';
import 'package:appflowy/plugins/database/application/field/field_controller.dart'; import 'package:appflowy/plugins/database/application/field/field_controller.dart';
import 'package:appflowy/plugins/database/application/field/field_info.dart'; import 'package:appflowy/plugins/database/application/field/field_info.dart';
@ -13,7 +15,6 @@ import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:collection/collection.dart'; import 'package:collection/collection.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_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class DatabasePropertyList extends StatefulWidget { class DatabasePropertyList extends StatefulWidget {
@ -43,6 +44,12 @@ class _DatabasePropertyListState extends State<DatabasePropertyList> {
)..add(const DatabasePropertyEvent.initial()); )..add(const DatabasePropertyEvent.initial());
} }
@override
void dispose() {
_popoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return BlocProvider<DatabasePropertyBloc>.value( return BlocProvider<DatabasePropertyBloc>.value(

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart'; import 'package:appflowy/mobile/presentation/bottom_sheet/show_mobile_bottom_sheet.dart';
@ -25,7 +27,6 @@ import 'package:collection/collection.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:fixnum/fixnum.dart'; import 'package:fixnum/fixnum.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 'package:nanoid/non_secure.dart'; import 'package:nanoid/non_secure.dart';
@ -64,6 +65,12 @@ class _MentionDateBlockState extends State<MentionDateBlock> {
late bool _includeTime = widget.includeTime; late bool _includeTime = widget.includeTime;
late DateTime? parsedDate = DateTime.tryParse(widget.date); late DateTime? parsedDate = DateTime.tryParse(widget.date);
@override
void dispose() {
mutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
if (parsedDate == null) { if (parsedDate == null) {

View File

@ -67,8 +67,9 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
bool? disableSearchIndexing, bool? disableSearchIndexing,
AIModelPB? model, AIModelPB? model,
}) { }) {
final payload = final payload = UpdateUserWorkspaceSettingPB(
UpdateUserWorkspaceSettingPB(workspaceId: userProfile.workspaceId); workspaceId: userProfile.workspaceId,
);
if (disableSearchIndexing != null) { if (disableSearchIndexing != null) {
payload.disableSearchIndexing = disableSearchIndexing; payload.disableSearchIndexing = disableSearchIndexing;
} }
@ -82,17 +83,16 @@ class SettingsAIBloc extends Bloc<SettingsAIEvent, SettingsAIState> {
FlowyResult<UserProfilePB, FlowyError> userProfileOrFailed, FlowyResult<UserProfilePB, FlowyError> userProfileOrFailed,
) => ) =>
userProfileOrFailed.fold( userProfileOrFailed.fold(
(newUserProfile) => (profile) => add(SettingsAIEvent.didReceiveUserProfile(profile)),
add(SettingsAIEvent.didReceiveUserProfile(newUserProfile)),
(err) => Log.error(err), (err) => Log.error(err),
); );
void _loadUserWorkspaceSetting() { void _loadUserWorkspaceSetting() {
final payload = UserWorkspaceIdPB(workspaceId: userProfile.workspaceId); final payload = UserWorkspaceIdPB(workspaceId: userProfile.workspaceId);
UserEventGetWorkspaceSetting(payload).send().then((result) { UserEventGetWorkspaceSetting(payload).send().then((result) {
result.fold((settins) { result.fold((settings) {
if (!isClosed) { if (!isClosed) {
add(SettingsAIEvent.didLoadAISetting(settins)); add(SettingsAIEvent.didLoadAISetting(settings));
} }
}, (err) { }, (err) {
Log.error(err); Log.error(err);

View File

@ -117,6 +117,10 @@ class SettingsPlanBloc extends Bloc<SettingsPlanEvent, SettingsPlanState> {
); );
}, },
cancelSubscription: () async { cancelSubscription: () async {
final newState = state
.mapOrNull(ready: (state) => state)
?.copyWith(downgradeProcessing: true);
emit(newState ?? state);
await _userService.cancelSubscription(workspaceId); await _userService.cancelSubscription(workspaceId);
add(const SettingsPlanEvent.started()); add(const SettingsPlanEvent.started());
}, },
@ -174,5 +178,6 @@ class SettingsPlanState with _$SettingsPlanState {
required WorkspaceSubscriptionPB subscription, required WorkspaceSubscriptionPB subscription,
required BillingPortalPB? billingPortal, required BillingPortalPB? billingPortal,
@Default(false) bool showSuccessDialog, @Default(false) bool showSuccessDialog,
@Default(false) bool downgradeProcessing,
}) = _Ready; }) = _Ready;
} }

View File

@ -1,8 +1,20 @@
import 'package:appflowy_backend/protobuf/flowy-user/workspace.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/workspace.pb.dart';
import 'package:intl/intl.dart';
final _storageNumberFormat = NumberFormat()
..maximumFractionDigits = 2
..minimumFractionDigits = 0;
extension PresentableUsage on WorkspaceUsagePB { extension PresentableUsage on WorkspaceUsagePB {
String get totalBlobInGb => String get totalBlobInGb =>
(totalBlobBytesLimit.toInt() / 1024 / 1024 / 1024).round().toString(); (totalBlobBytesLimit.toInt() / 1024 / 1024 / 1024).round().toString();
/// We use [NumberFormat] to format the current blob in GB.
///
/// Where the [totalBlobBytes] is the total blob bytes in bytes.
/// And [NumberFormat.maximumFractionDigits] is set to 2.
/// And [NumberFormat.minimumFractionDigits] is set to 0.
///
String get currentBlobInGb => String get currentBlobInGb =>
(totalBlobBytes.toInt() / 1024 / 1024 / 1024).round().toString(); _storageNumberFormat.format(totalBlobBytes.toInt() / 1024 / 1024 / 1024);
} }

View File

@ -1,5 +1,7 @@
import 'dart:io'; import 'dart:io';
import 'package:flutter/material.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/startup/tasks/app_window_size_manager.dart'; import 'package:appflowy/startup/tasks/app_window_size_manager.dart';
import 'package:appflowy/workspace/application/home/home_setting_bloc.dart'; import 'package:appflowy/workspace/application/home/home_setting_bloc.dart';
@ -9,7 +11,6 @@ import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart'; import 'package:appflowy/workspace/presentation/home/menu/sidebar/shared/sidebar_setting.dart';
import 'package:appflowy_backend/log.dart'; import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/user_profile.pb.dart';
import 'package:flutter/material.dart';
import 'package:hotkey_manager/hotkey_manager.dart'; import 'package:hotkey_manager/hotkey_manager.dart';
import 'package:provider/provider.dart'; import 'package:provider/provider.dart';
import 'package:scaled_app/scaled_app.dart'; import 'package:scaled_app/scaled_app.dart';
@ -186,14 +187,12 @@ class _HomeHotKeysState extends State<HomeHotKeys> {
@override @override
void initState() { void initState() {
super.initState(); super.initState();
_registerHotKeys(context); _registerHotKeys(context);
} }
@override @override
void didChangeDependencies() { void didChangeDependencies() {
super.didChangeDependencies(); super.didChangeDependencies();
_registerHotKeys(context); _registerHotKeys(context);
} }

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart'; import 'package:appflowy/workspace/application/tabs/tabs_bloc.dart';
import 'package:appflowy/workspace/presentation/home/home_sizes.dart'; import 'package:appflowy/workspace/presentation/home/home_sizes.dart';
import 'package:appflowy/workspace/presentation/home/tabs/flowy_tab.dart'; import 'package:appflowy/workspace/presentation/home/tabs/flowy_tab.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class TabsManager extends StatefulWidget { class TabsManager extends StatefulWidget {

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.dart';
import 'package:appflowy/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
import 'package:appflowy/user/application/notification_filter/notification_filter_bloc.dart'; import 'package:appflowy/user/application/notification_filter/notification_filter_bloc.dart';
import 'package:appflowy/user/application/reminder/reminder_bloc.dart'; import 'package:appflowy/user/application/reminder/reminder_bloc.dart';
@ -9,7 +11,6 @@ import 'package:appflowy/workspace/presentation/notifications/widgets/notificati
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-user/reminder.pb.dart';
import 'package:appflowy_popover/appflowy_popover.dart'; import 'package:appflowy_popover/appflowy_popover.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class NotificationDialog extends StatefulWidget { class NotificationDialog extends StatefulWidget {
@ -44,7 +45,7 @@ class _NotificationDialogState extends State<NotificationDialog>
@override @override
void dispose() { void dispose() {
_mutex.close(); _mutex.dispose();
_controller.removeListener(_updateState); _controller.removeListener(_updateState);
_controller.dispose(); _controller.dispose();
super.dispose(); super.dispose();

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/startup/startup.dart'; import 'package:appflowy/startup/startup.dart';
@ -10,18 +12,27 @@ import 'package:easy_localization/easy_localization.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:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/material.dart';
import 'package:flutter_bloc/flutter_bloc.dart'; import 'package:flutter_bloc/flutter_bloc.dart';
class NotificationButton extends StatelessWidget { class NotificationButton extends StatefulWidget {
const NotificationButton({ const NotificationButton({super.key});
super.key,
}); @override
State<NotificationButton> createState() => _NotificationButtonState();
}
class _NotificationButtonState extends State<NotificationButton> {
final mutex = PopoverMutex();
@override
void dispose() {
mutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final views = context.watch<SidebarSectionsBloc>().state.section.views; final views = context.watch<SidebarSectionsBloc>().state.section.views;
final mutex = PopoverMutex();
return BlocProvider<ReminderBloc>.value( return BlocProvider<ReminderBloc>.value(
value: getIt<ReminderBloc>(), value: getIt<ReminderBloc>(),

View File

@ -1,3 +1,5 @@
import 'package:flutter/material.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/document/presentation/editor_configuration.dart'; import 'package:appflowy/plugins/document/presentation/editor_configuration.dart';
@ -12,7 +14,6 @@ import 'package:fixnum/fixnum.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:provider/provider.dart'; import 'package:provider/provider.dart';
class NotificationItem extends StatefulWidget { class NotificationItem extends StatefulWidget {
@ -71,6 +72,12 @@ class _NotificationItemState extends State<NotificationItem> {
infoString = _buildInfoString(); infoString = _buildInfoString();
} }
@override
void dispose() {
mutex.dispose();
super.dispose();
}
String _buildInfoString() { String _buildInfoString() {
String scheduledString = String scheduledString =
_scheduledString(widget.scheduled, widget.includeTime); _scheduledString(widget.scheduled, widget.includeTime);

View File

@ -1,13 +1,13 @@
import 'package:appflowy/workspace/presentation/settings/shared/af_dropdown_menu_entry.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_dropdown.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart'; import 'package:appflowy/workspace/application/settings/ai/settings_ai_bloc.dart';
import 'package:appflowy/workspace/presentation/settings/shared/af_dropdown_menu_entry.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart'; import 'package:appflowy/workspace/presentation/settings/shared/settings_body.dart';
import 'package:appflowy/workspace/presentation/settings/shared/settings_dropdown.dart';
import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart'; import 'package:appflowy/workspace/presentation/widgets/toggle/toggle.dart';
import 'package:appflowy_backend/log.dart';
import 'package:appflowy_backend/protobuf/flowy-user/protobuf.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.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/spacing.dart'; import 'package:flowy_infra_ui/widget/spacing.dart';
@ -153,11 +153,9 @@ class _AISearchToggle extends StatelessWidget {
} else { } else {
return Toggle( return Toggle(
value: state.enableSearchIndexing, value: state.enableSearchIndexing,
onChanged: (_) { onChanged: (_) => context
context.read<SettingsAIBloc>().add( .read<SettingsAIBloc>()
const SettingsAIEvent.toggleAISearch(), .add(const SettingsAIEvent.toggleAISearch()),
);
},
); );
} }
}, },

View File

@ -47,7 +47,7 @@ class _SettingsPlanComparisonDialogState
Widget build(BuildContext context) { Widget build(BuildContext context) {
final isLM = Theme.of(context).isLightMode; final isLM = Theme.of(context).isLightMode;
return BlocListener<SettingsPlanBloc, SettingsPlanState>( return BlocConsumer<SettingsPlanBloc, SettingsPlanState>(
listener: (context, state) { listener: (context, state) {
final readyState = state.mapOrNull(ready: (state) => state); final readyState = state.mapOrNull(ready: (state) => state);
@ -82,7 +82,7 @@ class _SettingsPlanComparisonDialogState
currentSubscription = readyState.subscription; currentSubscription = readyState.subscription;
}); });
}, },
child: FlowyDialog( builder: (context, state) => FlowyDialog(
constraints: const BoxConstraints(maxWidth: 784, minWidth: 674), constraints: const BoxConstraints(maxWidth: 784, minWidth: 674),
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
@ -185,7 +185,16 @@ class _SettingsPlanComparisonDialogState
canDowngrade: canDowngrade:
currentSubscription.subscriptionPlan != currentSubscription.subscriptionPlan !=
SubscriptionPlanPB.None, SubscriptionPlanPB.None,
currentCanceled: currentSubscription.hasCanceled, currentCanceled: currentSubscription.hasCanceled ||
(context
.watch<SettingsPlanBloc>()
.state
.mapOrNull(
loading: (_) => true,
ready: (state) =>
state.downgradeProcessing,
) ??
false),
onSelected: () async { onSelected: () async {
if (currentSubscription.subscriptionPlan == if (currentSubscription.subscriptionPlan ==
SubscriptionPlanPB.None || SubscriptionPlanPB.None ||
@ -484,8 +493,9 @@ class _ActionButton extends StatelessWidget {
cursor: onPressed != null cursor: onPressed != null
? SystemMouseCursors.click ? SystemMouseCursors.click
: MouseCursor.defer, : MouseCursor.defer,
child: _drawGradientBorder( child: _drawBorder(
isLM: isLM, isLM: isLM,
isUpgrade: isUpgrade,
child: Container( child: Container(
height: 36, height: 36,
width: 148, width: 148,
@ -496,9 +506,7 @@ class _ActionButton extends StatelessWidget {
border: Border.all(color: Colors.transparent), border: Border.all(color: Colors.transparent),
borderRadius: BorderRadius.circular(14), borderRadius: BorderRadius.circular(14),
), ),
child: Center( child: Center(child: _drawText(label, isLM, isUpgrade)),
child: _drawText(label, isLM),
),
), ),
), ),
), ),
@ -509,13 +517,13 @@ class _ActionButton extends StatelessWidget {
); );
} }
Widget _drawText(String text, bool isLM) { Widget _drawText(String text, bool isLM, bool isUpgrade) {
final child = FlowyText( final child = FlowyText(
text, text,
fontSize: 14, fontSize: 14,
lineHeight: 1.2, lineHeight: 1.2,
fontWeight: useGradientBorder ? FontWeight.w600 : FontWeight.w500, fontWeight: useGradientBorder ? FontWeight.w600 : FontWeight.w500,
color: const Color(0xFFC49BEC), color: isUpgrade ? const Color(0xFFC49BEC) : null,
); );
if (!useGradientBorder || !isLM) { if (!useGradientBorder || !isLM) {
@ -536,18 +544,25 @@ class _ActionButton extends StatelessWidget {
); );
} }
Widget _drawGradientBorder({required bool isLM, required Widget child}) { Widget _drawBorder({
required bool isLM,
required bool isUpgrade,
required Widget child,
}) {
return Container( return Container(
padding: const EdgeInsets.all(2), padding: const EdgeInsets.all(2),
decoration: BoxDecoration( decoration: BoxDecoration(
gradient: LinearGradient( gradient: isUpgrade
transform: const GradientRotation(-1.2), ? LinearGradient(
stops: const [0.4, 1], transform: const GradientRotation(-1.2),
colors: [ stops: const [0.4, 1],
isLM ? const Color(0xFF251D37) : const Color(0xFF7459AD), colors: [
isLM ? const Color(0xFF7547C0) : const Color(0xFFDDC8FF), isLM ? const Color(0xFF251D37) : const Color(0xFF7459AD),
], isLM ? const Color(0xFF7547C0) : const Color(0xFFDDC8FF),
), ],
)
: null,
border: isUpgrade ? null : Border.all(),
borderRadius: BorderRadius.circular(16), borderRadius: BorderRadius.circular(16),
), ),
child: child, child: child,

View File

@ -80,11 +80,30 @@ class SettingsPlanView extends StatelessWidget {
} }
} }
class _CurrentPlanBox extends StatelessWidget { class _CurrentPlanBox extends StatefulWidget {
const _CurrentPlanBox({required this.subscription}); const _CurrentPlanBox({required this.subscription});
final WorkspaceSubscriptionPB subscription; final WorkspaceSubscriptionPB subscription;
@override
State<_CurrentPlanBox> createState() => _CurrentPlanBoxState();
}
class _CurrentPlanBoxState extends State<_CurrentPlanBox> {
late SettingsPlanBloc planBloc;
@override
void initState() {
super.initState();
planBloc = context.read<SettingsPlanBloc>();
}
@override
void didChangeDependencies() {
planBloc = context.read<SettingsPlanBloc>();
super.didChangeDependencies();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Stack( return Stack(
@ -105,13 +124,13 @@ class _CurrentPlanBox extends StatelessWidget {
children: [ children: [
const VSpace(4), const VSpace(4),
FlowyText.semibold( FlowyText.semibold(
subscription.label, widget.subscription.label,
fontSize: 24, fontSize: 24,
color: AFThemeExtension.of(context).strongText, color: AFThemeExtension.of(context).strongText,
), ),
const VSpace(8), const VSpace(8),
FlowyText.regular( FlowyText.regular(
subscription.info, widget.subscription.info,
fontSize: 16, fontSize: 16,
color: AFThemeExtension.of(context).strongText, color: AFThemeExtension.of(context).strongText,
maxLines: 3, maxLines: 3,
@ -124,10 +143,10 @@ class _CurrentPlanBox extends StatelessWidget {
onPressed: () => _openPricingDialog( onPressed: () => _openPricingDialog(
context, context,
context.read<SettingsPlanBloc>().workspaceId, context.read<SettingsPlanBloc>().workspaceId,
subscription, widget.subscription,
), ),
), ),
if (subscription.hasCanceled) ...[ if (widget.subscription.hasCanceled) ...[
const VSpace(12), const VSpace(12),
FlowyText( FlowyText(
LocaleKeys LocaleKeys
@ -149,10 +168,10 @@ class _CurrentPlanBox extends StatelessWidget {
separatorBuilder: () => const VSpace(4), separatorBuilder: () => const VSpace(4),
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
..._getPros(subscription.subscriptionPlan).map( ..._getPros(widget.subscription.subscriptionPlan).map(
(s) => _ProConItem(label: s), (s) => _ProConItem(label: s),
), ),
..._getCons(subscription.subscriptionPlan).map( ..._getCons(widget.subscription.subscriptionPlan).map(
(s) => _ProConItem(label: s, isPro: false), (s) => _ProConItem(label: s, isPro: false),
), ),
], ],
@ -185,7 +204,7 @@ class _CurrentPlanBox extends StatelessWidget {
String _canceledDate(BuildContext context) { String _canceledDate(BuildContext context) {
final appearance = context.read<AppearanceSettingsCubit>().state; final appearance = context.read<AppearanceSettingsCubit>().state;
return appearance.dateFormat.formatDate( return appearance.dateFormat.formatDate(
subscription.canceledAt.toDateTime(), widget.subscription.canceledAt.toDateTime(),
true, true,
appearance.timeFormat, appearance.timeFormat,
); );
@ -199,7 +218,7 @@ class _CurrentPlanBox extends StatelessWidget {
showDialog( showDialog(
context: context, context: context,
builder: (_) => BlocProvider<SettingsPlanBloc>.value( builder: (_) => BlocProvider<SettingsPlanBloc>.value(
value: context.read<SettingsPlanBloc>(), value: planBloc,
child: SettingsPlanComparisonDialog( child: SettingsPlanComparisonDialog(
workspaceId: workspaceId, workspaceId: workspaceId,
subscription: subscription, subscription: subscription,
@ -224,6 +243,7 @@ class _CurrentPlanBox extends StatelessWidget {
LocaleKeys.settings_planPage_planUsage_currentPlan_freeProFour.tr(), LocaleKeys.settings_planPage_planUsage_currentPlan_freeProFour.tr(),
LocaleKeys.settings_planPage_planUsage_currentPlan_freeProFive.tr(), LocaleKeys.settings_planPage_planUsage_currentPlan_freeProFive.tr(),
]; ];
List<String> _freeCons() => [ List<String> _freeCons() => [
LocaleKeys.settings_planPage_planUsage_currentPlan_freeConOne.tr(), LocaleKeys.settings_planPage_planUsage_currentPlan_freeConOne.tr(),
LocaleKeys.settings_planPage_planUsage_currentPlan_freeConTwo.tr(), LocaleKeys.settings_planPage_planUsage_currentPlan_freeConTwo.tr(),
@ -242,6 +262,7 @@ class _CurrentPlanBox extends StatelessWidget {
LocaleKeys.settings_planPage_planUsage_currentPlan_professionalProFive LocaleKeys.settings_planPage_planUsage_currentPlan_professionalProFive
.tr(), .tr(),
]; ];
List<String> _proCons() => [ List<String> _proCons() => [
LocaleKeys.settings_planPage_planUsage_currentPlan_professionalConOne LocaleKeys.settings_planPage_planUsage_currentPlan_professionalConOne
.tr(), .tr(),
@ -314,6 +335,11 @@ class _PlanUsageSummary extends StatelessWidget {
Expanded( Expanded(
child: _UsageBox( child: _UsageBox(
title: LocaleKeys.settings_planPage_planUsage_storageLabel.tr(), title: LocaleKeys.settings_planPage_planUsage_storageLabel.tr(),
replacementText: subscription.subscriptionPlan ==
SubscriptionPlanPB.Pro
? LocaleKeys.settings_planPage_planUsage_storageUnlimited
.tr()
: null,
label: LocaleKeys.settings_planPage_planUsage_storageUsage.tr( label: LocaleKeys.settings_planPage_planUsage_storageUsage.tr(
args: [ args: [
usage.currentBlobInGb, usage.currentBlobInGb,
@ -372,12 +398,16 @@ class _UsageBox extends StatelessWidget {
required this.title, required this.title,
required this.label, required this.label,
required this.value, required this.value,
this.replacementText,
}); });
final String title; final String title;
final String label; final String label;
final double value; final double value;
/// Replaces the progress indicator if not null
final String? replacementText;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Column( return Column(
@ -388,7 +418,21 @@ class _UsageBox extends StatelessWidget {
fontSize: 11, fontSize: 11,
color: AFThemeExtension.of(context).secondaryTextColor, color: AFThemeExtension.of(context).secondaryTextColor,
), ),
_PlanProgressIndicator(label: label, progress: value), if (replacementText != null) ...[
Row(
children: [
Flexible(
child: FlowyText.medium(
replacementText!,
fontSize: 11,
color: AFThemeExtension.of(context).secondaryTextColor,
),
),
],
),
] else ...[
_PlanProgressIndicator(label: label, progress: value),
],
], ],
); );
} }

View File

@ -1,11 +1,12 @@
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/plugins/base/emoji/emoji_picker.dart'; import 'package:appflowy/plugins/base/emoji/emoji_picker.dart';
import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart'; import 'package:appflowy/plugins/document/presentation/editor_plugins/base/selectable_svg_widget.dart';
import 'package:appflowy_editor/appflowy_editor.dart'; import 'package:appflowy_editor/appflowy_editor.dart';
import 'package:easy_localization/easy_localization.dart'; import 'package:easy_localization/easy_localization.dart';
import 'package:flowy_infra_ui/style_widget/decoration.dart'; import 'package:flowy_infra_ui/style_widget/decoration.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
SelectionMenuItem emojiMenuItem = SelectionMenuItem( SelectionMenuItem emojiMenuItem = SelectionMenuItem(
getName: LocaleKeys.document_plugins_emoji.tr, getName: LocaleKeys.document_plugins_emoji.tr,
@ -85,8 +86,8 @@ class EmojiSelectionMenu extends StatefulWidget {
class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> { class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> {
@override @override
void initState() { void initState() {
HardwareKeyboard.instance.addHandler(_handleGlobalKeyEvent);
super.initState(); super.initState();
HardwareKeyboard.instance.addHandler(_handleGlobalKeyEvent);
} }
bool _handleGlobalKeyEvent(KeyEvent event) { bool _handleGlobalKeyEvent(KeyEvent event) {
@ -95,9 +96,8 @@ class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> {
//triggers on esc //triggers on esc
widget.onExit(); widget.onExit();
return true; return true;
} else {
return false;
} }
return false;
} }
@override @override
@ -106,17 +106,10 @@ class _EmojiSelectionMenuState extends State<EmojiSelectionMenu> {
super.deactivate(); super.deactivate();
} }
@override
void dispose() {
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return FlowyEmojiPicker( return FlowyEmojiPicker(
onEmojiSelected: (_, emoji) { onEmojiSelected: (_, emoji) => widget.onSubmitted(emoji),
widget.onSubmitted(emoji);
},
); );
} }
} }

View File

@ -1,6 +1,8 @@
import 'package:flutter/material.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'emoji_picker.dart'; import 'emoji_picker.dart';
import 'emoji_picker_builder.dart'; import 'emoji_picker_builder.dart';
import 'models/emoji_category_models.dart'; import 'models/emoji_category_models.dart';
@ -29,8 +31,10 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
@override @override
void initState() { void initState() {
var initCategory = widget.state.emojiCategoryGroupList.indexWhere( super.initState();
(element) => element.category == widget.config.initCategory,
int initCategory = widget.state.emojiCategoryGroupList.indexWhere(
(el) => el.category == widget.config.initCategory,
); );
if (initCategory == -1) { if (initCategory == -1) {
initCategory = 0; initCategory = 0;
@ -42,27 +46,23 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
); );
_pageController = PageController(initialPage: initCategory); _pageController = PageController(initialPage: initCategory);
_emojiFocusNode.requestFocus(); _emojiFocusNode.requestFocus();
_emojiController.addListener(() { _emojiController.addListener(() {
final String query = _emojiController.text.toLowerCase(); final String query = _emojiController.text.toLowerCase();
if (query.isEmpty) { if (query.isEmpty) {
searchEmojiList.emoji.clear(); searchEmojiList.emoji.clear();
_pageController!.jumpToPage( _pageController!.jumpToPage(_tabController!.index);
_tabController!.index,
);
} else { } else {
searchEmojiList.emoji.clear(); searchEmojiList.emoji.clear();
for (final element in widget.state.emojiCategoryGroupList) { for (final element in widget.state.emojiCategoryGroupList) {
searchEmojiList.emoji.addAll( searchEmojiList.emoji.addAll(
element.emoji.where((item) { element.emoji
return item.name.toLowerCase().contains(query); .where((item) => item.name.toLowerCase().contains(query))
}).toList(), .toList(),
); );
} }
} }
setState(() {}); setState(() {});
}); });
super.initState();
} }
@override @override
@ -81,25 +81,17 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
type: MaterialType.transparency, type: MaterialType.transparency,
child: IconButton( child: IconButton(
padding: const EdgeInsets.only(bottom: 2), padding: const EdgeInsets.only(bottom: 2),
icon: Icon( icon: Icon(Icons.backspace, color: widget.config.backspaceColor),
Icons.backspace, onPressed: () => widget.state.onBackspacePressed!(),
color: widget.config.backspaceColor,
),
onPressed: () {
widget.state.onBackspacePressed!();
},
), ),
); );
} }
return const SizedBox.shrink(); return const SizedBox.shrink();
} }
bool isEmojiSearching() { bool isEmojiSearching() =>
final bool result = searchEmojiList.emoji.isNotEmpty || _emojiController.text.isNotEmpty;
searchEmojiList.emoji.isNotEmpty || _emojiController.text.isNotEmpty;
return result;
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
@ -213,15 +205,9 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
required Widget child, required Widget child,
}) { }) {
if (widget.config.buttonMode == ButtonMode.MATERIAL) { if (widget.config.buttonMode == ButtonMode.MATERIAL) {
return InkWell( return InkWell(onTap: onPressed, child: child);
onTap: onPressed,
child: child,
);
} }
return GestureDetector( return GestureDetector(onTap: onPressed, child: child);
onTap: onPressed,
child: child,
);
} }
Widget _buildPage(double emojiSize, EmojiCategoryGroup emojiCategoryGroup) { Widget _buildPage(double emojiSize, EmojiCategoryGroup emojiCategoryGroup) {
@ -275,9 +261,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
child: FittedBox( child: FittedBox(
child: Text( child: Text(
emoji.emoji, emoji.emoji,
style: TextStyle( style: TextStyle(fontSize: emojiSize),
fontSize: emojiSize,
),
), ),
), ),
), ),

View File

@ -1,3 +1,7 @@
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:appflowy/core/helpers/url_launcher.dart'; import 'package:appflowy/core/helpers/url_launcher.dart';
import 'package:appflowy/generated/locale_keys.g.dart'; import 'package:appflowy/generated/locale_keys.g.dart';
import 'package:appflowy/workspace/application/settings/supabase_cloud_setting_bloc.dart'; import 'package:appflowy/workspace/application/settings/supabase_cloud_setting_bloc.dart';
@ -15,9 +19,6 @@ 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:flowy_infra_ui/widget/error_page.dart'; import 'package:flowy_infra_ui/widget/error_page.dart';
import 'package:flowy_infra_ui/widget/flowy_tooltip.dart'; import 'package:flowy_infra_ui/widget/flowy_tooltip.dart';
import 'package:flutter/gestures.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';
class SettingSupabaseCloudView extends StatelessWidget { class SettingSupabaseCloudView extends StatelessWidget {
@ -265,13 +266,7 @@ class SupabaseInput extends StatefulWidget {
} }
class SupabaseInputState extends State<SupabaseInput> { class SupabaseInputState extends State<SupabaseInput> {
late TextEditingController _controller; late final _controller = TextEditingController(text: widget.url);
@override
void initState() {
super.initState();
_controller = TextEditingController(text: widget.url);
}
@override @override
void dispose() { void dispose() {

View File

@ -29,6 +29,12 @@ class _DateTimeSettingState extends State<DateTimeSetting> {
final timeSettingPopoverMutex = PopoverMutex(); final timeSettingPopoverMutex = PopoverMutex();
String? overlayIdentifier; String? overlayIdentifier;
@override
void dispose() {
timeSettingPopoverMutex.dispose();
super.dispose();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final List<Widget> children = [ final List<Widget> children = [

View File

@ -129,11 +129,6 @@ class NavigatorAlertDialog extends StatefulWidget {
} }
class _CreateFlowyAlertDialog extends State<NavigatorAlertDialog> { class _CreateFlowyAlertDialog extends State<NavigatorAlertDialog> {
@override
void initState() {
super.initState();
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return StyledDialog( return StyledDialog(

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.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:flowy_infra_ui/style_widget/hover.dart'; import 'package:flowy_infra_ui/style_widget/hover.dart';
import 'package:flutter/material.dart';
import 'package:styled_widget/styled_widget.dart'; import 'package:styled_widget/styled_widget.dart';
class PopoverActionList<T extends PopoverAction> extends StatefulWidget { class PopoverActionList<T extends PopoverAction> extends StatefulWidget {
@ -42,12 +43,12 @@ class PopoverActionList<T extends PopoverAction> extends StatefulWidget {
class _PopoverActionListState<T extends PopoverAction> class _PopoverActionListState<T extends PopoverAction>
extends State<PopoverActionList<T>> { extends State<PopoverActionList<T>> {
late PopoverController popoverController; final PopoverController popoverController = PopoverController();
@override @override
void initState() { void dispose() {
popoverController = PopoverController(); popoverController.close();
super.initState(); super.dispose();
} }
@override @override

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'package:appflowy/workspace/application/view/view_listener.dart'; import 'package:appflowy/workspace/application/view/view_listener.dart';
import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart'; import 'package:appflowy_backend/protobuf/flowy-folder/view.pb.dart';
import 'package:flowy_infra_ui/flowy_infra_ui.dart'; import 'package:flowy_infra_ui/flowy_infra_ui.dart';
import 'package:flutter/material.dart';
class ViewTabBarItem extends StatefulWidget { class ViewTabBarItem extends StatefulWidget {
const ViewTabBarItem({super.key, required this.view}); const ViewTabBarItem({super.key, required this.view});
@ -37,7 +38,5 @@ class _ViewTabBarItemState extends State<ViewTabBarItem> {
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) => FlowyText.medium(view.name);
return FlowyText.medium(view.name);
}
} }

View File

@ -1,7 +1,8 @@
import 'package:flutter/material.dart';
import 'dart:async'; import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:appflowy_backend/appflowy_backend.dart'; import 'package:appflowy_backend/appflowy_backend.dart';
void main() { void main() {
@ -36,21 +37,15 @@ class _MyAppState extends State<MyApp> {
// message was in flight, we want to discard the reply rather than calling // message was in flight, we want to discard the reply rather than calling
// setState to update our non-existent appearance. // setState to update our non-existent appearance.
if (!mounted) return; if (!mounted) return;
setState(() { setState(() => _platformVersion = platformVersion);
_platformVersion = platformVersion;
});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return MaterialApp( return MaterialApp(
home: Scaffold( home: Scaffold(
appBar: AppBar( appBar: AppBar(title: const Text('Plugin example app')),
title: const Text('Plugin example app'), body: Center(child: Text('Running on: $_platformVersion\n')),
),
body: Center(
child: Text('Running on: $_platformVersion\n'),
),
), ),
); );
} }

View File

@ -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';
@ -177,9 +178,7 @@ class PopoverState extends State<Popover> {
_rootEntry.addEntry(context, this, newEntry, widget.asBarrier); _rootEntry.addEntry(context, this, newEntry, widget.asBarrier);
} }
void close({ void close({bool notify = true}) {
bool notify = true,
}) {
if (_rootEntry.contains(this)) { if (_rootEntry.contains(this)) {
_rootEntry.removeEntry(this); _rootEntry.removeEntry(this);
if (notify) { if (notify) {
@ -286,9 +285,7 @@ class PopoverContainer extends StatefulWidget {
if (context is StatefulElement && context.state is PopoverContainerState) { if (context is StatefulElement && context.state is PopoverContainerState) {
return context.state as PopoverContainerState; return context.state as PopoverContainerState;
} }
final PopoverContainerState? result = return context.findAncestorStateOfType<PopoverContainerState>()!;
context.findAncestorStateOfType<PopoverContainerState>();
return result!;
} }
static PopoverContainerState? maybeOf(BuildContext context) { static PopoverContainerState? maybeOf(BuildContext context) {

View File

@ -2,10 +2,11 @@
import 'dart:ui'; import 'dart:ui';
import 'package:flowy_infra_ui/src/flowy_overlay/layout.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flowy_infra_ui/src/flowy_overlay/layout.dart';
/// Specifies how overlay are anchored to the SourceWidget /// Specifies how overlay are anchored to the SourceWidget
enum AnchorDirection { enum AnchorDirection {
// Corner aligned with a corner of the SourceWidget // Corner aligned with a corner of the SourceWidget
@ -341,18 +342,17 @@ class FlowyOverlayState extends State<FlowyOverlay> {
@override @override
void initState() { void initState() {
_keyboardShortcutBindings.addAll({
LogicalKeySet(LogicalKeyboardKey.escape): (identifier) {
remove(identifier);
},
});
super.initState(); super.initState();
_keyboardShortcutBindings.addAll({
LogicalKeySet(LogicalKeyboardKey.escape): (identifier) =>
remove(identifier),
});
} }
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final overlays = _overlayList.map((item) { final overlays = _overlayList.map((item) {
var widget = item.widget; Widget widget = item.widget;
// requestFocus will cause the children weird focus behaviors. // requestFocus will cause the children weird focus behaviors.
// item.focusNode.requestFocus(); // item.focusNode.requestFocus();
@ -390,15 +390,11 @@ class FlowyOverlayState extends State<FlowyOverlay> {
return MaterialApp( return MaterialApp(
theme: Theme.of(context), theme: Theme.of(context),
debugShowCheckedModeBanner: false, debugShowCheckedModeBanner: false,
home: Stack( home: Stack(children: children..addAll(overlays)),
children: children..addAll(overlays),
),
); );
} }
void _handleTapOnBackground() { void _handleTapOnBackground() => removeAll();
removeAll();
}
Widget? _renderBackground(List<Widget> overlays) { Widget? _renderBackground(List<Widget> overlays) {
Widget? child; Widget? child;

View File

@ -36,13 +36,7 @@ class StyledListView extends StatefulWidget {
/// State is public so this can easily be controlled externally /// State is public so this can easily be controlled externally
class StyledListViewState extends State<StyledListView> { class StyledListViewState extends State<StyledListView> {
late ScrollController scrollController; final scrollController = ScrollController();
@override
void initState() {
scrollController = ScrollController();
super.initState();
}
@override @override
void dispose() { void dispose() {
@ -50,15 +44,6 @@ class StyledListViewState extends State<StyledListView> {
super.dispose(); super.dispose();
} }
@override
void didUpdateWidget(StyledListView oldWidget) {
if (oldWidget.itemCount != widget.itemCount ||
oldWidget.itemExtent != widget.itemExtent) {
setState(() {});
}
super.didUpdateWidget(oldWidget);
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final contentSize = (widget.itemCount ?? 0.0) * (widget.itemExtent ?? 00.0); final contentSize = (widget.itemCount ?? 0.0) * (widget.itemExtent ?? 00.0);
@ -75,7 +60,7 @@ class StyledListViewState extends State<StyledListView> {
controller: scrollController, controller: scrollController,
itemExtent: widget.itemExtent, itemExtent: widget.itemExtent,
itemCount: widget.itemCount, itemCount: widget.itemCount,
itemBuilder: (c, i) => widget.itemBuilder(c, i), itemBuilder: widget.itemBuilder,
), ),
); );
return listContent; return listContent;

View File

@ -137,7 +137,6 @@ class FlowyTextFieldState extends State<FlowyTextField> {
void _onSubmitted(String text) { void _onSubmitted(String text) {
widget.onSubmitted?.call(text); widget.onSubmitted?.call(text);
if (widget.autoClearWhenDone) { if (widget.autoClearWhenDone) {
// using `controller.clear()` instead of `controller.text = ''` which will crash on Windows.
controller.clear(); controller.clear();
} }
} }
@ -154,7 +153,7 @@ class FlowyTextFieldState extends State<FlowyTextField> {
_onChanged(text); _onChanged(text);
} }
}, },
onSubmitted: (text) => _onSubmitted(text), onSubmitted: _onSubmitted,
onEditingComplete: widget.onEditingComplete, onEditingComplete: widget.onEditingComplete,
minLines: 1, minLines: 1,
maxLines: widget.maxLines, maxLines: widget.maxLines,

View File

@ -1,10 +1,11 @@
import 'dart:async'; import 'dart:async';
import 'dart:math' as math; import 'dart:math' as math;
import 'package:flowy_infra/size.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flowy_infra/size.dart';
class FlowyFormTextInput extends StatelessWidget { class FlowyFormTextInput extends StatelessWidget {
static EdgeInsets kDefaultTextInputPadding = static EdgeInsets kDefaultTextInputPadding =
EdgeInsets.only(bottom: Insets.sm, top: 4); EdgeInsets.only(bottom: Insets.sm, top: 4);
@ -162,10 +163,12 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
@override @override
void initState() { void initState() {
super.initState();
_controller = _controller =
widget.controller ?? TextEditingController(text: widget.initialValue); widget.controller ?? TextEditingController(text: widget.initialValue);
_focusNode = FocusNode( _focusNode = FocusNode(
debugLabel: widget.label ?? '', debugLabel: widget.label,
canRequestFocus: true,
onKeyEvent: (node, event) { onKeyEvent: (node, event) {
if (event.logicalKey == LogicalKeyboardKey.escape) { if (event.logicalKey == LogicalKeyboardKey.escape) {
widget.onEditingCancel?.call(); widget.onEditingCancel?.call();
@ -173,7 +176,6 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
} }
return KeyEventResult.ignored; return KeyEventResult.ignored;
}, },
canRequestFocus: true,
); );
// Listen for focus out events // Listen for focus out events
_focusNode _focusNode
@ -182,7 +184,6 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
if (widget.autoFocus ?? false) { if (widget.autoFocus ?? false) {
scheduleMicrotask(() => _focusNode.requestFocus()); scheduleMicrotask(() => _focusNode.requestFocus());
} }
super.initState();
} }
@override @override
@ -292,8 +293,10 @@ class ThinUnderlineBorder extends InputBorder {
bool get isOutline => false; bool get isOutline => false;
@override @override
UnderlineInputBorder copyWith( UnderlineInputBorder copyWith({
{BorderSide? borderSide, BorderRadius? borderRadius}) { BorderSide? borderSide,
BorderRadius? borderRadius,
}) {
return UnderlineInputBorder( return UnderlineInputBorder(
borderSide: borderSide ?? this.borderSide, borderSide: borderSide ?? this.borderSide,
borderRadius: borderRadius ?? this.borderRadius, borderRadius: borderRadius ?? this.borderRadius,
@ -301,14 +304,12 @@ class ThinUnderlineBorder extends InputBorder {
} }
@override @override
EdgeInsetsGeometry get dimensions { EdgeInsetsGeometry get dimensions =>
return EdgeInsets.only(bottom: borderSide.width); EdgeInsets.only(bottom: borderSide.width);
}
@override @override
UnderlineInputBorder scale(double t) { UnderlineInputBorder scale(double t) =>
return UnderlineInputBorder(borderSide: borderSide.scale(t)); UnderlineInputBorder(borderSide: borderSide.scale(t));
}
@override @override
Path getInnerPath(Rect rect, {TextDirection? textDirection}) { Path getInnerPath(Rect rect, {TextDirection? textDirection}) {

View File

@ -1,9 +1,10 @@
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:flowy_infra/time/duration.dart';
import 'package:flutter/services.dart'; import 'package:flutter/services.dart';
import 'package:flowy_infra/size.dart';
import 'package:flowy_infra/time/duration.dart';
import 'package:flowy_infra_ui/widget/rounded_button.dart';
class RoundedInputField extends StatefulWidget { class RoundedInputField extends StatefulWidget {
final String? hintText; final String? hintText;
final bool obscureText; final bool obscureText;
@ -60,33 +61,26 @@ class RoundedInputField extends StatefulWidget {
class _RoundedInputFieldState extends State<RoundedInputField> { class _RoundedInputFieldState extends State<RoundedInputField> {
String inputText = ""; String inputText = "";
bool obscuteText = false; bool obscureText = false;
@override @override
void initState() { void initState() {
obscuteText = widget.obscureText;
if (widget.controller != null) {
inputText = widget.controller!.text;
} else {
inputText = widget.initialValue ?? "";
}
super.initState(); super.initState();
obscureText = widget.obscureText;
inputText = widget.controller != null
? widget.controller!.text
: widget.initialValue ?? "";
} }
String? _suffixText() { String? _suffixText() => widget.maxLength != null
if (widget.maxLength != null) { ? ' ${widget.controller!.text.length}/${widget.maxLength}'
return ' ${widget.controller!.text.length}/${widget.maxLength}'; : null;
} else {
return null;
}
}
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
var borderColor = Color borderColor =
widget.normalBorderColor ?? Theme.of(context).colorScheme.outline; widget.normalBorderColor ?? Theme.of(context).colorScheme.outline;
var focusBorderColor = Color focusBorderColor =
widget.focusBorderColor ?? Theme.of(context).colorScheme.primary; widget.focusBorderColor ?? Theme.of(context).colorScheme.primary;
if (widget.errorText.isNotEmpty) { if (widget.errorText.isNotEmpty) {
@ -122,7 +116,7 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
}, },
cursorColor: cursorColor:
widget.cursorColor ?? Theme.of(context).colorScheme.primary, widget.cursorColor ?? Theme.of(context).colorScheme.primary,
obscureText: obscuteText, obscureText: obscureText,
style: widget.style ?? Theme.of(context).textTheme.bodyMedium, style: widget.style ?? Theme.of(context).textTheme.bodyMedium,
decoration: InputDecoration( decoration: InputDecoration(
contentPadding: widget.contentPadding, contentPadding: widget.contentPadding,
@ -134,17 +128,11 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
suffixText: _suffixText(), suffixText: _suffixText(),
counterText: "", counterText: "",
enabledBorder: OutlineInputBorder( enabledBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(color: borderColor, width: 1.0),
color: borderColor,
width: 1.0,
),
borderRadius: Corners.s10Border, borderRadius: Corners.s10Border,
), ),
focusedBorder: OutlineInputBorder( focusedBorder: OutlineInputBorder(
borderSide: BorderSide( borderSide: BorderSide(color: focusBorderColor, width: 1.0),
color: focusBorderColor,
width: 1.0,
),
borderRadius: Corners.s10Border, borderRadius: Corners.s10Border,
), ),
suffixIcon: obscureIcon(), suffixIcon: obscureIcon(),
@ -186,19 +174,11 @@ class _RoundedInputFieldState extends State<RoundedInputField> {
} }
assert(widget.obscureIcon != null && widget.obscureHideIcon != null); assert(widget.obscureIcon != null && widget.obscureHideIcon != null);
Widget? icon; final icon = obscureText ? widget.obscureIcon! : widget.obscureHideIcon!;
if (obscuteText) {
icon = widget.obscureIcon!;
} else {
icon = widget.obscureHideIcon!;
}
return RoundedImageButton( return RoundedImageButton(
size: iconWidth, size: iconWidth,
press: () { press: () => setState(() => obscureText = !obscureText),
obscuteText = !obscuteText;
setState(() {});
},
child: icon, child: icon,
); );
} }

View File

@ -53,11 +53,11 @@ packages:
dependency: "direct main" dependency: "direct main"
description: description:
path: "." path: "."
ref: "64c0be8" ref: e8ee051
resolved-ref: "64c0be88a113c2eece5512701527e7d11b8c9239" resolved-ref: e8ee051719eded6621ccdc2722f696411c020209
url: "https://github.com/AppFlowy-IO/appflowy-editor.git" url: "https://github.com/AppFlowy-IO/appflowy-editor.git"
source: git source: git
version: "2.5.1" version: "3.0.0"
appflowy_editor_plugins: appflowy_editor_plugins:
dependency: "direct main" dependency: "direct main"
description: description:

View File

@ -185,7 +185,7 @@ dependency_overrides:
appflowy_editor: appflowy_editor:
git: git:
url: https://github.com/AppFlowy-IO/appflowy-editor.git url: https://github.com/AppFlowy-IO/appflowy-editor.git
ref: "64c0be8" ref: "e8ee051"
appflowy_editor_plugins: appflowy_editor_plugins:
git: git:

View File

@ -633,6 +633,7 @@
"proBadge": "Pro", "proBadge": "Pro",
"memberProToggle": "Unlimited members", "memberProToggle": "Unlimited members",
"guestCollabToggle": "10 guest collaborators", "guestCollabToggle": "10 guest collaborators",
"storageUnlimited": "Unlimited storage with your Pro Plan",
"aiCredit": { "aiCredit": {
"title": "Add AppFlowy AI Credit", "title": "Add AppFlowy AI Credit",
"price": "5$", "price": "5$",