mirror of
https://github.com/AppFlowy-IO/AppFlowy.git
synced 2024-08-30 18:12:39 +00:00
fix: dispose of resources in time (#4625)
* fix: limit length when renaming views * chore: clean up database listeners * fix: dispose of controllers properly * fix: dispose of resources properly * fix: deleting filters with same name * chore: extend DatabaseTabBarItemBuilder * fix: null check on null value
This commit is contained in:
@ -44,7 +44,6 @@ class _MobileBottomSheetEditLinkWidgetState
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
textController.dispose();
|
textController.dispose();
|
||||||
hrefController.dispose();
|
hrefController.dispose();
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -27,14 +27,12 @@ class _MobileBottomSheetRenameWidgetState
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
controller = TextEditingController(text: widget.name);
|
controller = TextEditingController(text: widget.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,12 @@ class _MobileBoardContentState extends State<MobileBoardContent> {
|
|||||||
scrollController = ScrollController();
|
scrollController = ScrollController();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final screenWidth = MediaQuery.of(context).size.width;
|
final screenWidth = MediaQuery.of(context).size.width;
|
||||||
|
@ -19,6 +19,12 @@ class _MobileBoardTrailingState extends State<MobileBoardTrailing> {
|
|||||||
|
|
||||||
bool isEditing = false;
|
bool isEditing = false;
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final screenSize = MediaQuery.of(context).size;
|
final screenSize = MediaQuery.of(context).size;
|
||||||
|
@ -196,7 +196,6 @@ class _MobileFieldEditorState extends State<MobileFieldEditor> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
|
||||||
values = widget.defaultValues;
|
values = widget.defaultValues;
|
||||||
controller.text = values.name;
|
controller.text = values.name;
|
||||||
}
|
}
|
||||||
@ -204,7 +203,6 @@ class _MobileFieldEditorState extends State<MobileFieldEditor> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
controller.dispose();
|
controller.dispose();
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -83,6 +83,12 @@ class _NameAndIconState extends State<_NameAndIcon> {
|
|||||||
textEditingController.text = widget.view.name;
|
textEditingController.text = widget.view.name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
textEditingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return FlowyOptionTile.textField(
|
return FlowyOptionTile.textField(
|
||||||
|
@ -23,6 +23,7 @@ class _EditUsernameBottomSheetState extends State<EditUsernameBottomSheet> {
|
|||||||
late TextEditingController _textFieldController;
|
late TextEditingController _textFieldController;
|
||||||
|
|
||||||
final _formKey = GlobalKey<FormState>();
|
final _formKey = GlobalKey<FormState>();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
|
@ -16,6 +16,16 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
|||||||
final CheckboxCellController cellController;
|
final CheckboxCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<CheckboxCellEvent>(
|
on<CheckboxCellEvent>(
|
||||||
(event, emit) {
|
(event, emit) {
|
||||||
@ -35,17 +45,6 @@ class CheckboxCellBloc extends Bloc<CheckboxCellEvent, CheckboxCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (cellData) {
|
onCellChanged: (cellData) {
|
||||||
|
@ -32,6 +32,16 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
|||||||
final ChecklistCellBackendService _checklistCellService;
|
final ChecklistCellBackendService _checklistCellService;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<ChecklistCellEvent>(
|
on<ChecklistCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -79,16 +89,6 @@ class ChecklistCellBloc extends Bloc<ChecklistCellEvent, ChecklistCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (data) {
|
onCellChanged: (data) {
|
||||||
|
@ -17,6 +17,16 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
|||||||
final DateCellController cellController;
|
final DateCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<DateCellEvent>(
|
on<DateCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -35,15 +45,6 @@ class DateCellBloc extends Bloc<DateCellEvent, DateCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (data) {
|
onCellChanged: (data) {
|
||||||
|
@ -15,6 +15,16 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
|||||||
final NumberCellController cellController;
|
final NumberCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<NumberCellEvent>(
|
on<NumberCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -45,16 +55,6 @@ class NumberCellBloc extends Bloc<NumberCellEvent, NumberCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (cellContent) {
|
onCellChanged: (cellContent) {
|
||||||
|
@ -17,6 +17,16 @@ class SelectOptionCellBloc
|
|||||||
final SelectOptionCellController cellController;
|
final SelectOptionCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<SelectOptionCellEvent>(
|
on<SelectOptionCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -36,16 +46,6 @@ class SelectOptionCellBloc
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (selectOptionCellData) {
|
onCellChanged: (selectOptionCellData) {
|
||||||
|
@ -15,6 +15,16 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
|||||||
final TextCellController cellController;
|
final TextCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<TextCellEvent>(
|
on<TextCellEvent>(
|
||||||
(event, emit) {
|
(event, emit) {
|
||||||
@ -41,16 +51,6 @@ class TextCellBloc extends Bloc<TextCellEvent, TextCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (cellContent) {
|
onCellChanged: (cellContent) {
|
||||||
|
@ -17,6 +17,16 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
|||||||
final TimestampCellController cellController;
|
final TimestampCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<TimestampCellEvent>(
|
on<TimestampCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -35,16 +45,6 @@ class TimestampCellBloc extends Bloc<TimestampCellEvent, TimestampCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (data) {
|
onCellChanged: (data) {
|
||||||
|
@ -16,6 +16,16 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
|||||||
final URLCellController cellController;
|
final URLCellController cellController;
|
||||||
void Function()? _onCellChangedFn;
|
void Function()? _onCellChangedFn;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_onCellChangedFn != null) {
|
||||||
|
cellController.removeListener(_onCellChangedFn!);
|
||||||
|
_onCellChangedFn = null;
|
||||||
|
}
|
||||||
|
await cellController.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<URLCellEvent>(
|
on<URLCellEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -39,16 +49,6 @@ class URLCellBloc extends Bloc<URLCellEvent, URLCellState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_onCellChangedFn != null) {
|
|
||||||
cellController.removeListener(_onCellChangedFn!);
|
|
||||||
_onCellChangedFn = null;
|
|
||||||
}
|
|
||||||
await cellController.dispose();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
void _startListening() {
|
void _startListening() {
|
||||||
_onCellChangedFn = cellController.addListener(
|
_onCellChangedFn = cellController.addListener(
|
||||||
onCellChanged: (cellData) {
|
onCellChanged: (cellData) {
|
||||||
|
@ -1,52 +0,0 @@
|
|||||||
import 'dart:typed_data';
|
|
||||||
|
|
||||||
import 'package:appflowy/core/notification/grid_notification.dart';
|
|
||||||
import 'package:flowy_infra/notifier.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-error/protobuf.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
|
||||||
import 'package:dartz/dartz.dart';
|
|
||||||
|
|
||||||
/// Listener for database layout changes.
|
|
||||||
class DatabaseLayoutListener {
|
|
||||||
DatabaseLayoutListener(this.viewId);
|
|
||||||
|
|
||||||
final String viewId;
|
|
||||||
|
|
||||||
PublishNotifier<Either<DatabaseLayoutPB, FlowyError>>? _layoutNotifier =
|
|
||||||
PublishNotifier();
|
|
||||||
DatabaseNotificationListener? _listener;
|
|
||||||
|
|
||||||
void start({
|
|
||||||
required void Function(Either<DatabaseLayoutPB, FlowyError>)
|
|
||||||
onLayoutChanged,
|
|
||||||
}) {
|
|
||||||
_layoutNotifier?.addPublishListener(onLayoutChanged);
|
|
||||||
_listener = DatabaseNotificationListener(
|
|
||||||
objectId: viewId,
|
|
||||||
handler: _handler,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _handler(
|
|
||||||
DatabaseNotification ty,
|
|
||||||
Either<Uint8List, FlowyError> result,
|
|
||||||
) {
|
|
||||||
switch (ty) {
|
|
||||||
case DatabaseNotification.DidUpdateDatabaseLayout:
|
|
||||||
result.fold(
|
|
||||||
(payload) => _layoutNotifier?.value =
|
|
||||||
left(DatabaseLayoutMetaPB.fromBuffer(payload).layout),
|
|
||||||
(error) => _layoutNotifier?.value = right(error),
|
|
||||||
);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> stop() async {
|
|
||||||
await _listener?.stop();
|
|
||||||
_layoutNotifier?.dispose();
|
|
||||||
_layoutNotifier = null;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
import 'package:appflowy_backend/protobuf/flowy-error/errors.pb.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/setting_entities.pb.dart';
|
|
||||||
import 'setting_listener.dart';
|
|
||||||
import 'setting_service.dart';
|
|
||||||
|
|
||||||
typedef OnError = void Function(FlowyError);
|
|
||||||
typedef OnSettingUpdated = void Function(DatabaseViewSettingPB);
|
|
||||||
|
|
||||||
class SettingController {
|
|
||||||
SettingController({
|
|
||||||
required this.viewId,
|
|
||||||
}) : _settingBackendSvc = SettingBackendService(viewId: viewId),
|
|
||||||
_listener = DatabaseSettingListener(viewId: viewId) {
|
|
||||||
// Load setting
|
|
||||||
_settingBackendSvc.getSetting().then((result) {
|
|
||||||
result.fold(
|
|
||||||
(newSetting) => updateSetting(newSetting),
|
|
||||||
(err) => _onError?.call(err),
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
// Listen on the setting changes
|
|
||||||
_listener.start(
|
|
||||||
onSettingUpdated: (result) {
|
|
||||||
result.fold(
|
|
||||||
(newSetting) => updateSetting(newSetting),
|
|
||||||
(err) => _onError?.call(err),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
final String viewId;
|
|
||||||
final SettingBackendService _settingBackendSvc;
|
|
||||||
final DatabaseSettingListener _listener;
|
|
||||||
|
|
||||||
OnSettingUpdated? _onSettingUpdated;
|
|
||||||
OnError? _onError;
|
|
||||||
DatabaseViewSettingPB? _setting;
|
|
||||||
DatabaseViewSettingPB? get setting => _setting;
|
|
||||||
|
|
||||||
void startListening({
|
|
||||||
required OnSettingUpdated onSettingUpdated,
|
|
||||||
required OnError onError,
|
|
||||||
}) {
|
|
||||||
assert(_onSettingUpdated == null, 'Should call once');
|
|
||||||
assert(_onError == null, 'Should call once');
|
|
||||||
_onSettingUpdated = onSettingUpdated;
|
|
||||||
_onError = onError;
|
|
||||||
}
|
|
||||||
|
|
||||||
void updateSetting(DatabaseViewSettingPB newSetting) {
|
|
||||||
_setting = newSetting;
|
|
||||||
_onSettingUpdated?.call(newSetting);
|
|
||||||
}
|
|
||||||
|
|
||||||
void dispose() {
|
|
||||||
_onSettingUpdated = null;
|
|
||||||
_onError = null;
|
|
||||||
_listener.stop();
|
|
||||||
}
|
|
||||||
}
|
|
@ -131,6 +131,7 @@ class DatabaseTabBarBloc
|
|||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
for (final tabBar in state.tabBars) {
|
for (final tabBar in state.tabBars) {
|
||||||
await state.tabBarControllerByViewId[tabBar.viewId]?.dispose();
|
await state.tabBarControllerByViewId[tabBar.viewId]?.dispose();
|
||||||
|
tabBar.dispose();
|
||||||
}
|
}
|
||||||
return super.close();
|
return super.close();
|
||||||
}
|
}
|
||||||
@ -261,6 +262,10 @@ class DatabaseTabBar extends Equatable {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
List<Object?> get props => [view.hashCode];
|
List<Object?> get props => [view.hashCode];
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_builder.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
typedef OnViewUpdated = void Function(ViewPB newView);
|
typedef OnViewUpdated = void Function(ViewPB newView);
|
||||||
|
@ -33,7 +33,7 @@ import '../application/board_bloc.dart';
|
|||||||
import 'toolbar/board_setting_bar.dart';
|
import 'toolbar/board_setting_bar.dart';
|
||||||
import 'widgets/board_hidden_groups.dart';
|
import 'widgets/board_hidden_groups.dart';
|
||||||
|
|
||||||
class BoardPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
class BoardPageTabBarBuilderImpl extends DatabaseTabBarItemBuilder {
|
||||||
@override
|
@override
|
||||||
Widget content(
|
Widget content(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -26,6 +26,12 @@ class CalendarSettingBloc
|
|||||||
final DatabaseController _databaseController;
|
final DatabaseController _databaseController;
|
||||||
final DatabaseLayoutSettingListener _listener;
|
final DatabaseLayoutSettingListener _listener;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
await _listener.stop();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<CalendarSettingEvent>((event, emit) {
|
on<CalendarSettingEvent>((event, emit) {
|
||||||
event.when(
|
event.when(
|
||||||
@ -108,12 +114,6 @@ class CalendarSettingBloc
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
await _listener.stop();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@freezed
|
@freezed
|
||||||
|
@ -30,7 +30,7 @@ import 'calendar_day.dart';
|
|||||||
import 'layout/sizes.dart';
|
import 'layout/sizes.dart';
|
||||||
import 'toolbar/calendar_setting_bar.dart';
|
import 'toolbar/calendar_setting_bar.dart';
|
||||||
|
|
||||||
class CalendarPageTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
class CalendarPageTabBarBuilderImpl extends DatabaseTabBarItemBuilder {
|
||||||
@override
|
@override
|
||||||
Widget content(
|
Widget content(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -29,6 +29,7 @@ class CalculationsBloc extends Bloc<CalculationsEvent, CalculationsState> {
|
|||||||
@override
|
@override
|
||||||
Future<void> close() async {
|
Future<void> close() async {
|
||||||
_fieldController.removeListener(onFieldsListener: _onReceiveFields);
|
_fieldController.removeListener(onFieldsListener: _onReceiveFields);
|
||||||
|
await _calculationsListener.stop();
|
||||||
await super.close();
|
await super.close();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -73,7 +73,7 @@ class GridFilterMenuBloc
|
|||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> close() {
|
Future<void> close() async {
|
||||||
if (_onFilterFn != null) {
|
if (_onFilterFn != null) {
|
||||||
fieldController.removeListener(onFiltersListener: _onFilterFn!);
|
fieldController.removeListener(onFiltersListener: _onFilterFn!);
|
||||||
_onFilterFn = null;
|
_onFilterFn = null;
|
||||||
|
@ -45,7 +45,7 @@ class ToggleExtensionNotifier extends ChangeNotifier {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DesktopGridTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
class DesktopGridTabBarBuilderImpl extends DatabaseTabBarItemBuilder {
|
||||||
final _toggleExtension = ToggleExtensionNotifier();
|
final _toggleExtension = ToggleExtensionNotifier();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -86,6 +86,12 @@ class DesktopGridTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_toggleExtension.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
ValueKey _makeValueKey(DatabaseController controller) {
|
ValueKey _makeValueKey(DatabaseController controller) {
|
||||||
return ValueKey(controller.viewId);
|
return ValueKey(controller.viewId);
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ import 'widgets/header/mobile_grid_header.dart';
|
|||||||
import 'widgets/mobile_fab.dart';
|
import 'widgets/mobile_fab.dart';
|
||||||
import 'widgets/row/mobile_row.dart';
|
import 'widgets/row/mobile_row.dart';
|
||||||
|
|
||||||
class MobileGridTabBarBuilderImpl implements DatabaseTabBarItemBuilder {
|
class MobileGridTabBarBuilderImpl extends DatabaseTabBarItemBuilder {
|
||||||
@override
|
@override
|
||||||
Widget content(
|
Widget content(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
|
@ -35,7 +35,12 @@ class FilterMenu extends StatelessWidget {
|
|||||||
final List<Widget> children = [];
|
final List<Widget> children = [];
|
||||||
children.addAll(
|
children.addAll(
|
||||||
state.filters
|
state.filters
|
||||||
.map((filterInfo) => FilterMenuItem(filterInfo: filterInfo))
|
.map(
|
||||||
|
(filterInfo) => FilterMenuItem(
|
||||||
|
key: ValueKey(filterInfo.filter.id),
|
||||||
|
filterInfo: filterInfo,
|
||||||
|
),
|
||||||
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
@ -326,6 +326,12 @@ class _RowEnterRegionState extends State<_RowEnterRegion> {
|
|||||||
_rowStateNotifier = RegionStateNotifier();
|
_rowStateNotifier = RegionStateNotifier();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> dispose() async {
|
||||||
|
_rowStateNotifier.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return ChangeNotifierProvider.value(
|
return ChangeNotifierProvider.value(
|
||||||
@ -338,10 +344,4 @@ class _RowEnterRegionState extends State<_RowEnterRegion> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> dispose() async {
|
|
||||||
_rowStateNotifier.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -41,6 +41,12 @@ abstract class DatabaseTabBarItemBuilder {
|
|||||||
BuildContext context,
|
BuildContext context,
|
||||||
DatabaseController controller,
|
DatabaseController controller,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
/// Should be called in case a builder has resources it
|
||||||
|
/// needs to dispose of.
|
||||||
|
///
|
||||||
|
// If we add any logic in this method, add @mustCallSuper !
|
||||||
|
void dispose() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
class DatabaseTabBarView extends StatefulWidget {
|
class DatabaseTabBarView extends StatefulWidget {
|
||||||
|
@ -47,6 +47,16 @@ class CardBloc extends Bloc<CardEvent, CardState> {
|
|||||||
|
|
||||||
VoidCallback? _rowCallback;
|
VoidCallback? _rowCallback;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() async {
|
||||||
|
if (_rowCallback != null) {
|
||||||
|
_rowCache.removeRowListener(_rowCallback!);
|
||||||
|
_rowCallback = null;
|
||||||
|
}
|
||||||
|
await _rowListener.stop();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<CardEvent>(
|
on<CardEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
@ -73,16 +83,6 @@ class CardBloc extends Bloc<CardEvent, CardState> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
Future<void> close() async {
|
|
||||||
if (_rowCallback != null) {
|
|
||||||
_rowCache.removeRowListener(_rowCallback!);
|
|
||||||
_rowCallback = null;
|
|
||||||
}
|
|
||||||
await _rowListener.stop();
|
|
||||||
return super.close();
|
|
||||||
}
|
|
||||||
|
|
||||||
Future<void> _startListening() async {
|
Future<void> _startListening() async {
|
||||||
_rowCallback = _rowCache.addListener(
|
_rowCallback = _rowCache.addListener(
|
||||||
rowId: rowId,
|
rowId: rowId,
|
||||||
@ -113,7 +113,7 @@ List<CellContext> _makeCells(
|
|||||||
cellContexts.removeWhere((cellContext) {
|
cellContexts.removeWhere((cellContext) {
|
||||||
final fieldInfo = fieldController.getField(cellContext.fieldId);
|
final fieldInfo = fieldController.getField(cellContext.fieldId);
|
||||||
return fieldInfo == null ||
|
return fieldInfo == null ||
|
||||||
!fieldInfo.fieldSettings!.visibility.isVisibleState() ||
|
!(fieldInfo.fieldSettings?.visibility.isVisibleState() ?? false) ||
|
||||||
(groupFieldId != null && cellContext.fieldId == groupFieldId);
|
(groupFieldId != null && cellContext.fieldId == groupFieldId);
|
||||||
});
|
});
|
||||||
return cellContexts.toList();
|
return cellContexts.toList();
|
||||||
|
@ -1,10 +1,14 @@
|
|||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/cell/cell_controller_builder.dart';
|
|
||||||
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
|
||||||
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
|
||||||
|
import 'package:appflowy/plugins/database/application/cell/cell_controller.dart';
|
||||||
|
import 'package:appflowy/plugins/database/application/database_controller.dart';
|
||||||
|
import 'package:appflowy_backend/protobuf/flowy-database2/protobuf.dart';
|
||||||
|
|
||||||
|
import '../row/accessory/cell_accessory.dart';
|
||||||
|
import '../row/accessory/cell_shortcuts.dart';
|
||||||
|
import '../row/cells/cell_container.dart';
|
||||||
|
|
||||||
import 'editable_cell_skeleton/checkbox.dart';
|
import 'editable_cell_skeleton/checkbox.dart';
|
||||||
import 'editable_cell_skeleton/checklist.dart';
|
import 'editable_cell_skeleton/checklist.dart';
|
||||||
import 'editable_cell_skeleton/date.dart';
|
import 'editable_cell_skeleton/date.dart';
|
||||||
@ -13,9 +17,6 @@ import 'editable_cell_skeleton/select_option.dart';
|
|||||||
import 'editable_cell_skeleton/text.dart';
|
import 'editable_cell_skeleton/text.dart';
|
||||||
import 'editable_cell_skeleton/timestamp.dart';
|
import 'editable_cell_skeleton/timestamp.dart';
|
||||||
import 'editable_cell_skeleton/url.dart';
|
import 'editable_cell_skeleton/url.dart';
|
||||||
import '../row/accessory/cell_accessory.dart';
|
|
||||||
import '../row/accessory/cell_shortcuts.dart';
|
|
||||||
import '../row/cells/cell_container.dart';
|
|
||||||
|
|
||||||
enum EditableCellStyle {
|
enum EditableCellStyle {
|
||||||
desktopGrid,
|
desktopGrid,
|
||||||
@ -113,11 +114,12 @@ class EditableCellBuilder {
|
|||||||
CellContext cellContext, {
|
CellContext cellContext, {
|
||||||
required EditableCellSkinMap skinMap,
|
required EditableCellSkinMap skinMap,
|
||||||
}) {
|
}) {
|
||||||
final cellController = makeCellController(databaseController, cellContext);
|
final DatabaseController(:fieldController) = databaseController;
|
||||||
|
final fieldType = fieldController.getField(cellContext.fieldId)!.fieldType;
|
||||||
|
|
||||||
final key = ValueKey(
|
final key = ValueKey(
|
||||||
"${databaseController.viewId}${cellContext.fieldId}${cellContext.rowId}",
|
"${databaseController.viewId}${cellContext.fieldId}${cellContext.rowId}",
|
||||||
);
|
);
|
||||||
final fieldType = cellController.fieldType;
|
|
||||||
assert(skinMap.has(fieldType));
|
assert(skinMap.has(fieldType));
|
||||||
return switch (fieldType) {
|
return switch (fieldType) {
|
||||||
FieldType.Checkbox => EditableCheckboxCell(
|
FieldType.Checkbox => EditableCheckboxCell(
|
||||||
@ -239,6 +241,7 @@ abstract class GridCellState<T extends EditableCellWidget> extends State<T> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
widget.requestFocus.removeListener(onRequestFocus);
|
||||||
widget.requestFocus.dispose();
|
widget.requestFocus.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
@ -89,6 +89,7 @@ class _GridURLCellState extends GridEditableTextCell<EditableURLCell> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
widget._cellDataNotifier.dispose();
|
||||||
_textEditingController.dispose();
|
_textEditingController.dispose();
|
||||||
cellBloc.close();
|
cellBloc.close();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
|
@ -78,13 +78,13 @@ class MobileRowDetailURLCellSkin extends IEditableURLCellSkin {
|
|||||||
const [];
|
const [];
|
||||||
|
|
||||||
void _showURLEditor(BuildContext context, URLCellBloc bloc, String content) {
|
void _showURLEditor(BuildContext context, URLCellBloc bloc, String content) {
|
||||||
|
final controller = TextEditingController(text: content);
|
||||||
showMobileBottomSheet(
|
showMobileBottomSheet(
|
||||||
context,
|
context,
|
||||||
title: LocaleKeys.board_mobile_editURL.tr(),
|
title: LocaleKeys.board_mobile_editURL.tr(),
|
||||||
showHeader: true,
|
showHeader: true,
|
||||||
showCloseButton: true,
|
showCloseButton: true,
|
||||||
builder: (_) {
|
builder: (_) {
|
||||||
final controller = TextEditingController(text: content);
|
|
||||||
return TextField(
|
return TextField(
|
||||||
controller: controller,
|
controller: controller,
|
||||||
autofocus: true,
|
autofocus: true,
|
||||||
@ -95,6 +95,6 @@ class MobileRowDetailURLCellSkin extends IEditableURLCellSkin {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
).then((_) => controller.dispose());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -184,6 +184,14 @@ class _ChecklistItemState extends State<ChecklistItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textController.dispose();
|
||||||
|
_focusNode.dispose();
|
||||||
|
_debounceOnChanged?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void didUpdateWidget(ChecklistItem oldWidget) {
|
void didUpdateWidget(ChecklistItem oldWidget) {
|
||||||
super.didUpdateWidget(oldWidget);
|
super.didUpdateWidget(oldWidget);
|
||||||
@ -300,6 +308,12 @@ class _NewTaskItemState extends State<NewTaskItem> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textEditingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
|
@ -37,6 +37,7 @@ class _SelectOptionCellEditorState extends State<SelectOptionCellEditor> {
|
|||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
popoverMutex.dispose();
|
popoverMutex.dispose();
|
||||||
|
textEditingController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -162,7 +162,6 @@ class _SelectOptionTextFieldState extends State<SelectOptionTextField> {
|
|||||||
},
|
},
|
||||||
),
|
),
|
||||||
child: SingleChildScrollView(
|
child: SingleChildScrollView(
|
||||||
controller: ScrollController(),
|
|
||||||
scrollDirection: Axis.horizontal,
|
scrollDirection: Axis.horizontal,
|
||||||
child: Wrap(spacing: 4, children: children),
|
child: Wrap(spacing: 4, children: children),
|
||||||
),
|
),
|
||||||
|
@ -108,7 +108,8 @@ class _FindMenuState extends State<FindMenu> {
|
|||||||
widget.searchService.currentSelectedIndex.removeListener(_setState);
|
widget.searchService.currentSelectedIndex.removeListener(_setState);
|
||||||
widget.searchService.dispose();
|
widget.searchService.dispose();
|
||||||
findTextEditingController.removeListener(_searchPattern);
|
findTextEditingController.removeListener(_searchPattern);
|
||||||
|
findTextEditingController.dispose();
|
||||||
|
findTextFieldFocusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -241,6 +242,12 @@ class _ReplaceMenuState extends State<ReplaceMenu> {
|
|||||||
late final FocusNode replaceTextFieldFocusNode;
|
late final FocusNode replaceTextFieldFocusNode;
|
||||||
final replaceTextEditingController = TextEditingController();
|
final replaceTextEditingController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
replaceTextEditingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Row(
|
return Row(
|
||||||
|
@ -351,6 +351,12 @@ class CoverColorPicker extends StatefulWidget {
|
|||||||
class _CoverColorPickerState extends State<CoverColorPicker> {
|
class _CoverColorPickerState extends State<CoverColorPicker> {
|
||||||
final scrollController = ScrollController();
|
final scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Container(
|
return Container(
|
||||||
@ -375,12 +381,6 @@ class _CoverColorPickerState extends State<CoverColorPicker> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
super.dispose();
|
|
||||||
scrollController.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _buildColorItems(List<ColorOption> options, String? selectedColor) {
|
Widget _buildColorItems(List<ColorOption> options, String? selectedColor) {
|
||||||
return Row(
|
return Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
@ -110,9 +110,13 @@ class _NetworkImageUrlInputState extends State<NetworkImageUrlInput> {
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
urlController.addListener(() {
|
urlController.addListener(() => setState(() {}));
|
||||||
setState(() {});
|
}
|
||||||
});
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
urlController.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
|
@ -120,6 +120,12 @@ class _MathInputTextFieldState extends State<MathInputTextField> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
textEditingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return SizedBox(
|
return SizedBox(
|
||||||
|
@ -187,10 +187,10 @@ class MathEquationBlockComponentWidgetState
|
|||||||
}
|
}
|
||||||
|
|
||||||
void showEditingDialog() {
|
void showEditingDialog() {
|
||||||
|
final controller = TextEditingController(text: formula);
|
||||||
showDialog(
|
showDialog(
|
||||||
context: context,
|
context: context,
|
||||||
builder: (context) {
|
builder: (context) {
|
||||||
final controller = TextEditingController(text: formula);
|
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
backgroundColor: Theme.of(context).canvasColor,
|
backgroundColor: Theme.of(context).canvasColor,
|
||||||
title: Text(
|
title: Text(
|
||||||
@ -234,7 +234,7 @@ class MathEquationBlockComponentWidgetState
|
|||||||
actionsAlignment: MainAxisAlignment.spaceAround,
|
actionsAlignment: MainAxisAlignment.spaceAround,
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
).then((_) => controller.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateMathEquation(String mathEquation, BuildContext context) {
|
void updateMathEquation(String mathEquation, BuildContext context) {
|
||||||
|
@ -478,7 +478,6 @@ class _ToolbarItemListViewState extends State<_ToolbarItemListView> {
|
|||||||
void dispose() {
|
void dispose() {
|
||||||
widget.editorState.selectionNotifier
|
widget.editorState.selectionNotifier
|
||||||
.removeListener(_debounceUpdatePilotPosition);
|
.removeListener(_debounceUpdatePilotPosition);
|
||||||
|
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -134,6 +134,13 @@ class _InlineActionsHandlerState extends State<InlineActionsHandler> {
|
|||||||
startOffset = widget.editorState.selection?.endIndex ?? 0;
|
startOffset = widget.editorState.selection?.endIndex ?? 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
_focusNode.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Focus(
|
return Focus(
|
||||||
|
@ -28,6 +28,13 @@ class TrashPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _TrashPageState extends State<TrashPage> {
|
class _TrashPageState extends State<TrashPage> {
|
||||||
final ScrollController _scrollController = ScrollController();
|
final ScrollController _scrollController = ScrollController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_scrollController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
const horizontalPadding = 80.0;
|
const horizontalPadding = 80.0;
|
||||||
|
@ -28,6 +28,13 @@ class EncryptSecretScreen extends StatefulWidget {
|
|||||||
|
|
||||||
class _EncryptSecretScreenState extends State<EncryptSecretScreen> {
|
class _EncryptSecretScreenState extends State<EncryptSecretScreen> {
|
||||||
final TextEditingController _textEditingController = TextEditingController();
|
final TextEditingController _textEditingController = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_textEditingController.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -24,13 +24,19 @@ class MobileWorkspaceStartScreen extends StatefulWidget {
|
|||||||
class _MobileWorkspaceStartScreenState
|
class _MobileWorkspaceStartScreenState
|
||||||
extends State<MobileWorkspaceStartScreen> {
|
extends State<MobileWorkspaceStartScreen> {
|
||||||
WorkspacePB? selectedWorkspace;
|
WorkspacePB? selectedWorkspace;
|
||||||
|
final TextEditingController controller = TextEditingController();
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final style = Theme.of(context);
|
final style = Theme.of(context);
|
||||||
final size = MediaQuery.of(context).size;
|
final size = MediaQuery.of(context).size;
|
||||||
const double spacing = 16.0;
|
const double spacing = 16.0;
|
||||||
final TextEditingController controller = TextEditingController();
|
|
||||||
final List<DropdownMenuEntry<WorkspacePB>> workspaceEntries =
|
final List<DropdownMenuEntry<WorkspacePB>> workspaceEntries =
|
||||||
<DropdownMenuEntry<WorkspacePB>>[];
|
<DropdownMenuEntry<WorkspacePB>>[];
|
||||||
for (final WorkspacePB workspace in widget.workspaceState.workspaces) {
|
for (final WorkspacePB workspace in widget.workspaceState.workspaces) {
|
||||||
|
@ -22,6 +22,12 @@ class TabsBloc extends Bloc<TabsEvent, TabsState> {
|
|||||||
|
|
||||||
late final MenuSharedState menuSharedState;
|
late final MenuSharedState menuSharedState;
|
||||||
|
|
||||||
|
@override
|
||||||
|
Future<void> close() {
|
||||||
|
state.dispose();
|
||||||
|
return super.close();
|
||||||
|
}
|
||||||
|
|
||||||
void _dispatch() {
|
void _dispatch() {
|
||||||
on<TabsEvent>(
|
on<TabsEvent>(
|
||||||
(event, emit) async {
|
(event, emit) async {
|
||||||
|
@ -98,4 +98,10 @@ class TabsState {
|
|||||||
currentIndex: newIndex ?? currentIndex,
|
currentIndex: newIndex ?? currentIndex,
|
||||||
pageManagers: pageManagers ?? _pageManagers,
|
pageManagers: pageManagers ?? _pageManagers,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
for (final manager in pageManagers) {
|
||||||
|
manager.dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -253,6 +253,10 @@ class PageManager {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void dispose() {
|
||||||
|
_notifier.dispose();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class HomeTopBar extends StatelessWidget {
|
class HomeTopBar extends StatelessWidget {
|
||||||
|
@ -498,6 +498,7 @@ class _SingleInnerViewItemState extends State<SingleInnerViewItem> {
|
|||||||
title: LocaleKeys.disclosureAction_rename.tr(),
|
title: LocaleKeys.disclosureAction_rename.tr(),
|
||||||
autoSelectAllText: true,
|
autoSelectAllText: true,
|
||||||
value: widget.view.name,
|
value: widget.view.name,
|
||||||
|
maxLength: 256,
|
||||||
confirm: (newValue) {
|
confirm: (newValue) {
|
||||||
context.read<ViewBloc>().add(ViewEvent.rename(newValue));
|
context.read<ViewBloc>().add(ViewEvent.rename(newValue));
|
||||||
},
|
},
|
||||||
|
@ -25,6 +25,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
|
|||||||
final FocusNode _emojiFocusNode = FocusNode();
|
final FocusNode _emojiFocusNode = FocusNode();
|
||||||
EmojiCategoryGroup searchEmojiList =
|
EmojiCategoryGroup searchEmojiList =
|
||||||
EmojiCategoryGroup(EmojiCategory.SEARCH, <Emoji>[]);
|
EmojiCategoryGroup(EmojiCategory.SEARCH, <Emoji>[]);
|
||||||
|
final scrollController = ScrollController();
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@ -70,6 +71,7 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
|
|||||||
_emojiFocusNode.dispose();
|
_emojiFocusNode.dispose();
|
||||||
_pageController?.dispose();
|
_pageController?.dispose();
|
||||||
_tabController?.dispose();
|
_tabController?.dispose();
|
||||||
|
scrollController.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -224,8 +226,6 @@ class DefaultEmojiPickerViewState extends State<DefaultEmojiPickerView>
|
|||||||
|
|
||||||
Widget _buildPage(double emojiSize, EmojiCategoryGroup emojiCategoryGroup) {
|
Widget _buildPage(double emojiSize, EmojiCategoryGroup emojiCategoryGroup) {
|
||||||
// Display notice if recent has no entries yet
|
// Display notice if recent has no entries yet
|
||||||
final scrollController = ScrollController();
|
|
||||||
|
|
||||||
if (emojiCategoryGroup.category == EmojiCategory.RECENT &&
|
if (emojiCategoryGroup.category == EmojiCategory.RECENT &&
|
||||||
emojiCategoryGroup.emoji.isEmpty) {
|
emojiCategoryGroup.emoji.isEmpty) {
|
||||||
return _buildNoRecent();
|
return _buildNoRecent();
|
||||||
|
@ -277,6 +277,12 @@ class CloudURLInputState extends State<CloudURLInput> {
|
|||||||
_controller = TextEditingController(text: widget.url);
|
_controller = TextEditingController(text: widget.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
@ -306,12 +312,6 @@ class CloudURLInputState extends State<CloudURLInput> {
|
|||||||
onChanged: widget.onChanged,
|
onChanged: widget.onChanged,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class AppFlowyCloudEnableSync extends StatelessWidget {
|
class AppFlowyCloudEnableSync extends StatelessWidget {
|
||||||
|
@ -273,6 +273,12 @@ class SupabaseInputState extends State<SupabaseInput> {
|
|||||||
_controller = TextEditingController(text: widget.url);
|
_controller = TextEditingController(text: widget.url);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
@ -298,12 +304,6 @@ class SupabaseInputState extends State<SupabaseInput> {
|
|||||||
onChanged: widget.onChanged,
|
onChanged: widget.onChanged,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
class SupabaseSelfhostTip extends StatelessWidget {
|
class SupabaseSelfhostTip extends StatelessWidget {
|
||||||
|
@ -138,10 +138,10 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void showKeyListenerDialog(BuildContext widgetContext) {
|
void showKeyListenerDialog(BuildContext widgetContext) {
|
||||||
|
final controller = TextEditingController(text: shortcutEvent.command);
|
||||||
showDialog(
|
showDialog(
|
||||||
context: widgetContext,
|
context: widgetContext,
|
||||||
builder: (builderContext) {
|
builder: (builderContext) {
|
||||||
final controller = TextEditingController(text: shortcutEvent.command);
|
|
||||||
final formKey = GlobalKey<FormState>();
|
final formKey = GlobalKey<FormState>();
|
||||||
return AlertDialog(
|
return AlertDialog(
|
||||||
title: Text(LocaleKeys.settings_shortcuts_updateShortcutStep.tr()),
|
title: Text(LocaleKeys.settings_shortcuts_updateShortcutStep.tr()),
|
||||||
@ -184,7 +184,7 @@ class ShortcutsListTile extends StatelessWidget {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
).then((_) => controller.dispose());
|
||||||
}
|
}
|
||||||
|
|
||||||
String? _validateForConflicts(BuildContext context, String command) {
|
String? _validateForConflicts(BuildContext context, String command) {
|
||||||
|
@ -246,6 +246,13 @@ class UserNameInputState extends State<UserNameInput> {
|
|||||||
_controller = TextEditingController(text: widget.name);
|
_controller = TextEditingController(text: widget.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
_debounce?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return TextField(
|
return TextField(
|
||||||
@ -277,13 +284,6 @@ class UserNameInputState extends State<UserNameInput> {
|
|||||||
},
|
},
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
_controller.dispose();
|
|
||||||
_debounce?.cancel();
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@visibleForTesting
|
@visibleForTesting
|
||||||
|
@ -19,6 +19,7 @@ class NavigatorTextFieldDialog extends StatefulWidget {
|
|||||||
required this.value,
|
required this.value,
|
||||||
required this.confirm,
|
required this.confirm,
|
||||||
this.cancel,
|
this.cancel,
|
||||||
|
this.maxLength,
|
||||||
});
|
});
|
||||||
|
|
||||||
final String value;
|
final String value;
|
||||||
@ -26,6 +27,7 @@ class NavigatorTextFieldDialog extends StatefulWidget {
|
|||||||
final void Function()? cancel;
|
final void Function()? cancel;
|
||||||
final void Function(String) confirm;
|
final void Function(String) confirm;
|
||||||
final bool autoSelectAllText;
|
final bool autoSelectAllText;
|
||||||
|
final int? maxLength;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<NavigatorTextFieldDialog> createState() =>
|
State<NavigatorTextFieldDialog> createState() =>
|
||||||
@ -38,6 +40,7 @@ class _NavigatorTextFieldDialogState extends State<NavigatorTextFieldDialog> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
|
super.initState();
|
||||||
newValue = widget.value;
|
newValue = widget.value;
|
||||||
controller.text = newValue;
|
controller.text = newValue;
|
||||||
if (widget.autoSelectAllText) {
|
if (widget.autoSelectAllText) {
|
||||||
@ -46,7 +49,12 @@ class _NavigatorTextFieldDialogState extends State<NavigatorTextFieldDialog> {
|
|||||||
extentOffset: newValue.length,
|
extentOffset: newValue.length,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
super.initState();
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
controller.dispose();
|
||||||
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@ -63,9 +71,12 @@ class _NavigatorTextFieldDialogState extends State<NavigatorTextFieldDialog> {
|
|||||||
FlowyFormTextInput(
|
FlowyFormTextInput(
|
||||||
hintText: LocaleKeys.dialogCreatePageNameHint.tr(),
|
hintText: LocaleKeys.dialogCreatePageNameHint.tr(),
|
||||||
controller: controller,
|
controller: controller,
|
||||||
textStyle: Theme.of(context).textTheme.bodySmall?.copyWith(
|
textStyle: Theme.of(context)
|
||||||
fontSize: FontSizes.s16,
|
.textTheme
|
||||||
),
|
.bodySmall
|
||||||
|
?.copyWith(fontSize: FontSizes.s16),
|
||||||
|
maxLength: widget.maxLength,
|
||||||
|
showCounter: false,
|
||||||
autoFocus: true,
|
autoFocus: true,
|
||||||
onChanged: (text) {
|
onChanged: (text) {
|
||||||
newValue = text;
|
newValue = text;
|
||||||
|
@ -65,8 +65,10 @@ class _RenameViewPopoverState extends State<RenameViewPopover> {
|
|||||||
width: 220,
|
width: 220,
|
||||||
child: FlowyTextField(
|
child: FlowyTextField(
|
||||||
controller: _controller,
|
controller: _controller,
|
||||||
|
maxLength: 256,
|
||||||
onSubmitted: _updateViewName,
|
onSubmitted: _updateViewName,
|
||||||
onCanceled: () => _updateViewName(_controller.text),
|
onCanceled: () => _updateViewName(_controller.text),
|
||||||
|
showCounter: false,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
|
@ -48,9 +48,3 @@ class PublishNotifier<T> extends ChangeNotifier {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class Notifier extends ChangeNotifier {
|
|
||||||
void notify() {
|
|
||||||
notifyListeners();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
@ -30,6 +30,12 @@ class _KeyboardScreenState extends State<KeyboardScreen> {
|
|||||||
final TextEditingController _controller =
|
final TextEditingController _controller =
|
||||||
TextEditingController(text: 'Hello Flowy');
|
TextEditingController(text: 'Hello Flowy');
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
_controller.dispose();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
|
@ -45,7 +45,9 @@ class StyledSingleChildScrollViewState
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
// scrollController.dispose();
|
if (widget.controller == null) {
|
||||||
|
scrollController.dispose();
|
||||||
|
}
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ class FlowyTextFieldState extends State<FlowyTextField> {
|
|||||||
focusNode.addListener(notifyDidEndEditing);
|
focusNode.addListener(notifyDidEndEditing);
|
||||||
|
|
||||||
controller = widget.controller ?? TextEditingController();
|
controller = widget.controller ?? TextEditingController();
|
||||||
|
|
||||||
if (widget.text != null) {
|
if (widget.text != null) {
|
||||||
controller.text = widget.text!;
|
controller.text = widget.text!;
|
||||||
}
|
}
|
||||||
@ -95,6 +96,19 @@ class FlowyTextFieldState extends State<FlowyTextField> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@override
|
||||||
|
void dispose() {
|
||||||
|
focusNode.removeListener(notifyDidEndEditing);
|
||||||
|
if (widget.focusNode == null) {
|
||||||
|
focusNode.dispose();
|
||||||
|
}
|
||||||
|
if (widget.controller == null) {
|
||||||
|
controller.dispose();
|
||||||
|
}
|
||||||
|
_debounceOnChanged?.cancel();
|
||||||
|
super.dispose();
|
||||||
|
}
|
||||||
|
|
||||||
void _debounceOnChangedText(Duration duration, String text) {
|
void _debounceOnChangedText(Duration duration, String text) {
|
||||||
_debounceOnChanged?.cancel();
|
_debounceOnChanged?.cancel();
|
||||||
_debounceOnChanged = Timer(duration, () async {
|
_debounceOnChanged = Timer(duration, () async {
|
||||||
@ -200,15 +214,6 @@ class FlowyTextFieldState extends State<FlowyTextField> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
|
||||||
void dispose() {
|
|
||||||
focusNode.removeListener(notifyDidEndEditing);
|
|
||||||
if (widget.focusNode == null) {
|
|
||||||
focusNode.dispose();
|
|
||||||
}
|
|
||||||
super.dispose();
|
|
||||||
}
|
|
||||||
|
|
||||||
void notifyDidEndEditing() {
|
void notifyDidEndEditing() {
|
||||||
if (!focusNode.hasFocus) {
|
if (!focusNode.hasFocus) {
|
||||||
if (controller.text.isNotEmpty && widget.submitOnLeave) {
|
if (controller.text.isNotEmpty && widget.submitOnLeave) {
|
||||||
@ -222,8 +227,7 @@ class FlowyTextFieldState extends State<FlowyTextField> {
|
|||||||
String? _suffixText() {
|
String? _suffixText() {
|
||||||
if (widget.maxLength != null) {
|
if (widget.maxLength != null) {
|
||||||
return ' ${controller.text.length}/${widget.maxLength}';
|
return ' ${controller.text.length}/${widget.maxLength}';
|
||||||
} else {
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@ -17,6 +17,8 @@ class FlowyFormTextInput extends StatelessWidget {
|
|||||||
final TextStyle? textStyle;
|
final TextStyle? textStyle;
|
||||||
final TextAlign textAlign;
|
final TextAlign textAlign;
|
||||||
final int? maxLines;
|
final int? maxLines;
|
||||||
|
final int? maxLength;
|
||||||
|
final bool showCounter;
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final TextCapitalization? capitalization;
|
final TextCapitalization? capitalization;
|
||||||
final Function(String)? onChanged;
|
final Function(String)? onChanged;
|
||||||
@ -24,8 +26,8 @@ class FlowyFormTextInput extends StatelessWidget {
|
|||||||
final Function(bool)? onFocusChanged;
|
final Function(bool)? onFocusChanged;
|
||||||
final Function(FocusNode)? onFocusCreated;
|
final Function(FocusNode)? onFocusCreated;
|
||||||
|
|
||||||
const FlowyFormTextInput(
|
const FlowyFormTextInput({
|
||||||
{Key? key,
|
super.key,
|
||||||
this.label,
|
this.label,
|
||||||
this.autoFocus,
|
this.autoFocus,
|
||||||
this.initialValue,
|
this.initialValue,
|
||||||
@ -39,8 +41,10 @@ class FlowyFormTextInput extends StatelessWidget {
|
|||||||
this.capitalization,
|
this.capitalization,
|
||||||
this.textStyle,
|
this.textStyle,
|
||||||
this.textAlign = TextAlign.center,
|
this.textAlign = TextAlign.center,
|
||||||
this.maxLines})
|
this.maxLines,
|
||||||
: super(key: key);
|
this.maxLength,
|
||||||
|
this.showCounter = true,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -57,16 +61,17 @@ class FlowyFormTextInput extends StatelessWidget {
|
|||||||
onFocusChanged: onFocusChanged,
|
onFocusChanged: onFocusChanged,
|
||||||
controller: controller,
|
controller: controller,
|
||||||
maxLines: maxLines,
|
maxLines: maxLines,
|
||||||
inputDecoration: InputDecoration(
|
maxLength: maxLength,
|
||||||
isDense: true,
|
showCounter: showCounter,
|
||||||
contentPadding: contentPadding ?? kDefaultTextInputPadding,
|
contentPadding: contentPadding ?? kDefaultTextInputPadding,
|
||||||
border: const ThinUnderlineBorder(
|
hintText: hintText,
|
||||||
borderSide: BorderSide(width: 5, color: Colors.red)),
|
|
||||||
hintStyle: Theme.of(context)
|
hintStyle: Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium!
|
.bodyMedium!
|
||||||
.copyWith(color: Theme.of(context).hintColor.withOpacity(0.7)),
|
.copyWith(color: Theme.of(context).hintColor.withOpacity(0.7)),
|
||||||
hintText: hintText,
|
isDense: true,
|
||||||
|
inputBorder: const ThinUnderlineBorder(
|
||||||
|
borderSide: BorderSide(width: 5, color: Colors.red),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -82,6 +87,8 @@ class StyledSearchTextInput extends StatefulWidget {
|
|||||||
final IconData? icon;
|
final IconData? icon;
|
||||||
final String? initialValue;
|
final String? initialValue;
|
||||||
final int? maxLines;
|
final int? maxLines;
|
||||||
|
final int? maxLength;
|
||||||
|
final bool showCounter;
|
||||||
final TextEditingController? controller;
|
final TextEditingController? controller;
|
||||||
final TextCapitalization? capitalization;
|
final TextCapitalization? capitalization;
|
||||||
final TextInputType? type;
|
final TextInputType? type;
|
||||||
@ -89,11 +96,14 @@ class StyledSearchTextInput extends StatefulWidget {
|
|||||||
final bool? autoValidate;
|
final bool? autoValidate;
|
||||||
final bool? enableSuggestions;
|
final bool? enableSuggestions;
|
||||||
final bool? autoCorrect;
|
final bool? autoCorrect;
|
||||||
|
final bool isDense;
|
||||||
final String? errorText;
|
final String? errorText;
|
||||||
final String? hintText;
|
final String? hintText;
|
||||||
|
final TextStyle? hintStyle;
|
||||||
final Widget? prefixIcon;
|
final Widget? prefixIcon;
|
||||||
final Widget? suffixIcon;
|
final Widget? suffixIcon;
|
||||||
final InputDecoration? inputDecoration;
|
final InputDecoration? inputDecoration;
|
||||||
|
final InputBorder? inputBorder;
|
||||||
|
|
||||||
final Function(String)? onChanged;
|
final Function(String)? onChanged;
|
||||||
final Function()? onEditingComplete;
|
final Function()? onEditingComplete;
|
||||||
@ -105,7 +115,7 @@ class StyledSearchTextInput extends StatefulWidget {
|
|||||||
final VoidCallback? onTap;
|
final VoidCallback? onTap;
|
||||||
|
|
||||||
const StyledSearchTextInput({
|
const StyledSearchTextInput({
|
||||||
Key? key,
|
super.key,
|
||||||
this.label,
|
this.label,
|
||||||
this.autoFocus = false,
|
this.autoFocus = false,
|
||||||
this.obscureText = false,
|
this.obscureText = false,
|
||||||
@ -118,6 +128,7 @@ class StyledSearchTextInput extends StatefulWidget {
|
|||||||
this.autoValidate = false,
|
this.autoValidate = false,
|
||||||
this.enableSuggestions = true,
|
this.enableSuggestions = true,
|
||||||
this.autoCorrect = true,
|
this.autoCorrect = true,
|
||||||
|
this.isDense = false,
|
||||||
this.errorText,
|
this.errorText,
|
||||||
this.style,
|
this.style,
|
||||||
this.contentPadding,
|
this.contentPadding,
|
||||||
@ -133,9 +144,13 @@ class StyledSearchTextInput extends StatefulWidget {
|
|||||||
this.onSaved,
|
this.onSaved,
|
||||||
this.onTap,
|
this.onTap,
|
||||||
this.hintText,
|
this.hintText,
|
||||||
|
this.hintStyle,
|
||||||
this.capitalization,
|
this.capitalization,
|
||||||
this.maxLines,
|
this.maxLines,
|
||||||
}) : super(key: key);
|
this.maxLength,
|
||||||
|
this.showCounter = false,
|
||||||
|
this.inputBorder,
|
||||||
|
});
|
||||||
|
|
||||||
@override
|
@override
|
||||||
StyledSearchTextInputState createState() => StyledSearchTextInputState();
|
StyledSearchTextInputState createState() => StyledSearchTextInputState();
|
||||||
@ -175,7 +190,9 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
|
if (widget.controller == null) {
|
||||||
_controller.dispose();
|
_controller.dispose();
|
||||||
|
}
|
||||||
_focusNode.dispose();
|
_focusNode.dispose();
|
||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
@ -208,20 +225,25 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
|
|||||||
showCursor: true,
|
showCursor: true,
|
||||||
enabled: widget.enabled,
|
enabled: widget.enabled,
|
||||||
maxLines: widget.maxLines,
|
maxLines: widget.maxLines,
|
||||||
|
maxLength: widget.maxLength,
|
||||||
textCapitalization: widget.capitalization ?? TextCapitalization.none,
|
textCapitalization: widget.capitalization ?? TextCapitalization.none,
|
||||||
textAlign: widget.textAlign,
|
textAlign: widget.textAlign,
|
||||||
decoration: widget.inputDecoration ??
|
decoration: widget.inputDecoration ??
|
||||||
InputDecoration(
|
InputDecoration(
|
||||||
prefixIcon: widget.prefixIcon,
|
prefixIcon: widget.prefixIcon,
|
||||||
suffixIcon: widget.suffixIcon,
|
suffixIcon: widget.suffixIcon,
|
||||||
|
counterText: "",
|
||||||
|
suffixText: widget.showCounter ? _suffixText() : "",
|
||||||
contentPadding: widget.contentPadding ?? EdgeInsets.all(Insets.m),
|
contentPadding: widget.contentPadding ?? EdgeInsets.all(Insets.m),
|
||||||
border: const OutlineInputBorder(borderSide: BorderSide.none),
|
border: widget.inputBorder ??
|
||||||
isDense: true,
|
const OutlineInputBorder(borderSide: BorderSide.none),
|
||||||
|
isDense: widget.isDense,
|
||||||
icon: widget.icon == null ? null : Icon(widget.icon),
|
icon: widget.icon == null ? null : Icon(widget.icon),
|
||||||
errorText: widget.errorText,
|
errorText: widget.errorText,
|
||||||
errorMaxLines: 2,
|
errorMaxLines: 2,
|
||||||
hintText: widget.hintText,
|
hintText: widget.hintText,
|
||||||
hintStyle: Theme.of(context)
|
hintStyle: widget.hintStyle ??
|
||||||
|
Theme.of(context)
|
||||||
.textTheme
|
.textTheme
|
||||||
.bodyMedium!
|
.bodyMedium!
|
||||||
.copyWith(color: Theme.of(context).hintColor),
|
.copyWith(color: Theme.of(context).hintColor),
|
||||||
@ -230,6 +252,13 @@ class StyledSearchTextInputState extends State<StyledSearchTextInput> {
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
String? _suffixText() {
|
||||||
|
if (widget.controller != null && widget.maxLength != null) {
|
||||||
|
return ' ${widget.controller!.text.length}/${widget.maxLength}';
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
class ThinUnderlineBorder extends InputBorder {
|
class ThinUnderlineBorder extends InputBorder {
|
||||||
|
Reference in New Issue
Block a user