diff --git a/lib/stateManagement/openFiles/openFileTypes.dart b/lib/stateManagement/openFiles/openFileTypes.dart index 27c56486..dea271d3 100644 --- a/lib/stateManagement/openFiles/openFileTypes.dart +++ b/lib/stateManagement/openFiles/openFileTypes.dart @@ -47,7 +47,6 @@ abstract class OpenFileData with HasUuid, Undoable, Disposable, HasUndoHistory { final ValueNotifier loadingState = ValueNotifier(LoadingState.notLoaded); bool keepOpenAsHidden = false; final ChangeNotifier contentNotifier = ChangeNotifier(); - final ScrollController scrollController = ScrollController(); bool canBeReloaded = true; OpenFileData(String name, this.path, { required this.type, String? secondaryName, this.icon, this.iconColor }) : @@ -120,6 +119,5 @@ abstract class OpenFileData with HasUuid, Undoable, Disposable, HasUndoHistory { secondaryName.dispose(); _hasUnsavedChanges.dispose(); contentNotifier.dispose(); - scrollController.dispose(); } } diff --git a/lib/widgets/FileHierarchyExplorer/FileExplorer.dart b/lib/widgets/FileHierarchyExplorer/FileExplorer.dart index f21936f2..5f7aee03 100644 --- a/lib/widgets/FileHierarchyExplorer/FileExplorer.dart +++ b/lib/widgets/FileHierarchyExplorer/FileExplorer.dart @@ -21,7 +21,6 @@ class FileExplorer extends ChangeNotifierWidget { } class _FileExplorerState extends ChangeNotifierState { - final scrollController = ScrollController(); bool isDroppingFile = false; bool expandSearch = false; diff --git a/lib/widgets/FileHierarchyExplorer/HierarchyFlatList.dart b/lib/widgets/FileHierarchyExplorer/HierarchyFlatList.dart index 06c701fc..034b0c78 100644 --- a/lib/widgets/FileHierarchyExplorer/HierarchyFlatList.dart +++ b/lib/widgets/FileHierarchyExplorer/HierarchyFlatList.dart @@ -29,6 +29,12 @@ class _HierarchyFlatListState extends ChangeNotifierState { regenerateFlatTree(); } + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { if (openHierarchyManager.filteredTreeIsDirty.value) { @@ -44,7 +50,6 @@ class _HierarchyFlatListState extends ChangeNotifierState { builder: (context, isHovering) { isCursorInside = isHovering; return SmoothScrollBuilder( - controller: scrollController, builder: (context, controller, physics) { return ListView.builder( controller: controller, diff --git a/lib/widgets/FileHierarchyExplorer/datFilesSelector.dart b/lib/widgets/FileHierarchyExplorer/datFilesSelector.dart index 9281d3be..9e39ff56 100644 --- a/lib/widgets/FileHierarchyExplorer/datFilesSelector.dart +++ b/lib/widgets/FileHierarchyExplorer/datFilesSelector.dart @@ -41,7 +41,6 @@ class _DatSelectorWidget extends StatefulWidget { } class _DatSelectorWidgetState extends State<_DatSelectorWidget> { - final controller = ScrollController(); List<(String, BoolProp)>? files; bool? multiSelectToggleType; @@ -75,7 +74,6 @@ class _DatSelectorWidgetState extends State<_DatSelectorWidget> { ConstrainedBox( constraints: BoxConstraints(maxHeight: min(windowHeight - 300, windowHeight * 0.8)), child: SmoothSingleChildScrollView( - controller: controller, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/FileHierarchyExplorer/fileMetaEditor.dart b/lib/widgets/FileHierarchyExplorer/fileMetaEditor.dart index d67b895c..ae17ba55 100644 --- a/lib/widgets/FileHierarchyExplorer/fileMetaEditor.dart +++ b/lib/widgets/FileHierarchyExplorer/fileMetaEditor.dart @@ -43,14 +43,6 @@ class FileMetaEditor extends ChangeNotifierWidget { } class _FileMetaEditorState extends ChangeNotifierState { - final scrollController = ScrollController(); - - @override - void dispose() { - scrollController.dispose(); - super.dispose(); - } - _EditorType get editorType { var file = openHierarchyManager.selectedEntry.value; if (file == null) @@ -90,7 +82,6 @@ class _FileMetaEditorState extends ChangeNotifierState { key: Key(openHierarchyManager.selectedEntry.value?.uuid ?? "noGroup"), child: SmoothSingleChildScrollView( stepSize: 60, - controller: scrollController, child: Padding( padding: const EdgeInsets.all(8.0), child: entry != null ? getEditor()(entry) : makeFallback(null), diff --git a/lib/widgets/filesView/FileDetailsEditor.dart b/lib/widgets/filesView/FileDetailsEditor.dart index c40bf41d..6aee78e5 100644 --- a/lib/widgets/filesView/FileDetailsEditor.dart +++ b/lib/widgets/filesView/FileDetailsEditor.dart @@ -21,8 +21,6 @@ class FileDetailsEditor extends ChangeNotifierWidget { } class _FileDetailsEditorState extends ChangeNotifierState { - final scrollController = ScrollController(); - @override Widget build(BuildContext context) { return Column( @@ -33,7 +31,6 @@ class _FileDetailsEditorState extends ChangeNotifierState { Expanded( child: SmoothSingleChildScrollView( stepSize: 60, - controller: scrollController, child: Padding( padding: const EdgeInsets.all(8.0), child: _notifierBuilders( diff --git a/lib/widgets/filesView/fileTabView.dart b/lib/widgets/filesView/fileTabView.dart index e77e123f..f33b4282 100644 --- a/lib/widgets/filesView/fileTabView.dart +++ b/lib/widgets/filesView/fileTabView.dart @@ -45,6 +45,12 @@ class _FileTabViewState extends ChangeNotifierState { super.onNotified(); } + @override + void dispose() { + tabBarScrollController.dispose(); + super.dispose(); + } + void scrollTabIntoView(String uuid) { const tabWidth = 200.0; var viewWidth = (context.findRenderObject() as RenderBox).size.width; diff --git a/lib/widgets/filesView/types/TextFileEditor.dart b/lib/widgets/filesView/types/TextFileEditor.dart index f9028456..39388b41 100644 --- a/lib/widgets/filesView/types/TextFileEditor.dart +++ b/lib/widgets/filesView/types/TextFileEditor.dart @@ -129,6 +129,7 @@ class _TextFileEditorState extends ChangeNotifierState { void dispose() { widget.fileContent.text.removeListener(onFileContentChange); goToLineSubscription?.cancel(); + scrollController.dispose(); super.dispose(); } diff --git a/lib/widgets/filesView/types/bnkPlaylistEditor/BnkPlaylistEditor.dart b/lib/widgets/filesView/types/bnkPlaylistEditor/BnkPlaylistEditor.dart index 390940e9..2a44127d 100644 --- a/lib/widgets/filesView/types/bnkPlaylistEditor/BnkPlaylistEditor.dart +++ b/lib/widgets/filesView/types/bnkPlaylistEditor/BnkPlaylistEditor.dart @@ -60,6 +60,12 @@ class _BnkPlaylistEditorState extends State { super.initState(); } + @override + void dispose() { + scrollController.dispose(); + super.dispose(); + } + @override Widget build(BuildContext context) { if (widget.playlist.loadingState.value != LoadingState.loaded) { diff --git a/lib/widgets/filesView/types/effect/EstFileEditor.dart b/lib/widgets/filesView/types/effect/EstFileEditor.dart index 1d6960e1..433324a5 100644 --- a/lib/widgets/filesView/types/effect/EstFileEditor.dart +++ b/lib/widgets/filesView/types/effect/EstFileEditor.dart @@ -31,8 +31,6 @@ class EstFileEditor extends ChangeNotifierWidget { } class _EstFileEditorState extends ChangeNotifierState { - final scrollController = ScrollController(); - @override void initState() { widget.file.load(); @@ -80,7 +78,6 @@ class _EstFileEditorState extends ChangeNotifierState { ); } return SmoothSingleChildScrollView( - controller: scrollController, child: ChangeNotifierBuilder( notifier: widget.file.records, builder: (context) { diff --git a/lib/widgets/filesView/types/fonts/FontsManager.dart b/lib/widgets/filesView/types/fonts/FontsManager.dart index 236c8d7b..8a7cd31e 100644 --- a/lib/widgets/filesView/types/fonts/FontsManager.dart +++ b/lib/widgets/filesView/types/fonts/FontsManager.dart @@ -28,8 +28,6 @@ class FontsManager extends ChangeNotifierWidget { } class __McdFontsManagerState extends ChangeNotifierState { - final scrollController = ScrollController(); - @override Widget build(BuildContext context) { int iStart = 0; @@ -56,7 +54,6 @@ class __McdFontsManagerState extends ChangeNotifierState { "" ]; return SmoothSingleChildScrollView( - controller: scrollController, child: ColumnSeparated( children: [ Table( @@ -241,8 +238,6 @@ class _FontOverrideIdsSelector extends StatefulWidget { } class _FontOverrideIdsSelectorState extends State<_FontOverrideIdsSelector> { - final scrollController = ScrollController(); - @override Widget build(BuildContext context) { var blockedFontIds = McdData.fontOverrides @@ -263,7 +258,6 @@ class _FontOverrideIdsSelectorState extends State<_FontOverrideIdsSelector> { child: Padding( padding: const EdgeInsets.all(16.0), child: SmoothSingleChildScrollView( - controller: scrollController, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.stretch, diff --git a/lib/widgets/filesView/types/fonts/mcdEditor.dart b/lib/widgets/filesView/types/fonts/mcdEditor.dart index c7e266a5..ff38bc25 100644 --- a/lib/widgets/filesView/types/fonts/mcdEditor.dart +++ b/lib/widgets/filesView/types/fonts/mcdEditor.dart @@ -162,6 +162,7 @@ class _McdEditorBodyState extends ChangeNotifierState<_McdEditorBody> { void dispose() { search.dispose(); isRegex.dispose(); + scrollController.dispose(); super.dispose(); } diff --git a/lib/widgets/filesView/types/genericTable/tableEditor.dart b/lib/widgets/filesView/types/genericTable/tableEditor.dart index 4c908e85..a1330c43 100644 --- a/lib/widgets/filesView/types/genericTable/tableEditor.dart +++ b/lib/widgets/filesView/types/genericTable/tableEditor.dart @@ -141,6 +141,7 @@ class _TableEditorState extends ChangeNotifierState { for (var prop in columnSearch) prop.dispose(); widget.config.disposeConfig(); + scrollController.dispose(); super.dispose(); } diff --git a/lib/widgets/filesView/types/wem/wspFileEditor.dart b/lib/widgets/filesView/types/wem/wspFileEditor.dart index 18be24c4..65a0db64 100644 --- a/lib/widgets/filesView/types/wem/wspFileEditor.dart +++ b/lib/widgets/filesView/types/wem/wspFileEditor.dart @@ -15,8 +15,6 @@ class WspFileEditor extends StatefulWidget { } class _WspFileEditorState extends State { - final controller = ScrollController(); - @override void initState() { widget.wsp.load().then((_) => setState(() {})); @@ -26,7 +24,6 @@ class _WspFileEditorState extends State { @override Widget build(BuildContext context) { return SmoothScrollBuilder( - controller: controller, builder: (context, controller, physics) => ListView.builder( controller: controller, physics: physics, diff --git a/lib/widgets/filesView/types/xml/xmlActions/XmlActionsEditor.dart b/lib/widgets/filesView/types/xml/xmlActions/XmlActionsEditor.dart index d2807901..f1865672 100644 --- a/lib/widgets/filesView/types/xml/xmlActions/XmlActionsEditor.dart +++ b/lib/widgets/filesView/types/xml/xmlActions/XmlActionsEditor.dart @@ -30,8 +30,6 @@ class XmlActionsEditor extends XmlArrayEditor { } class _XmlActionsEditorState extends XmlArrayEditorState { - final scrollController = ScrollController(); - @override Widget build(BuildContext context) { var actions = getChildProps().toList(); @@ -39,7 +37,6 @@ class _XmlActionsEditorState extends XmlArrayEditorState { fit: StackFit.expand, children: [ SmoothSingleChildScrollView( - controller: scrollController, child: _backgroundDeselectArea( child: XmlJumpToLineEventWrapper( file: widget.root.file!, diff --git a/lib/widgets/layout/outliner.dart b/lib/widgets/layout/outliner.dart index 1377d2cd..6c06e6be 100644 --- a/lib/widgets/layout/outliner.dart +++ b/lib/widgets/layout/outliner.dart @@ -24,7 +24,6 @@ class Outliner extends ChangeNotifierWidget { class _OutlinerState extends ChangeNotifierState { final StringProp search = StringProp("", fileId: null); - final scrollController = ScrollController(); @override void dispose() { @@ -57,7 +56,6 @@ class _OutlinerState extends ChangeNotifierState { : null; return xmlProp != null ? SmoothSingleChildScrollView( stepSize: 60, - controller: scrollController, child: makeOutliner(), ) : Container(); } diff --git a/lib/widgets/layout/searchPanel.dart b/lib/widgets/layout/searchPanel.dart index 000484f9..4730ece7 100644 --- a/lib/widgets/layout/searchPanel.dart +++ b/lib/widgets/layout/searchPanel.dart @@ -52,7 +52,6 @@ class _SearchPanelState extends State { final ValueListNotifier searchResults = ValueListNotifier([], fileId: null); final isSearching = ValueNotifier(false); final Mutex cancelMutex = Mutex(); - final scrollController = ScrollController(); late final void Function() updateSearchStream; Set prevOpenFileUuids = {}; // common options @@ -453,7 +452,6 @@ class _SearchPanelState extends State { if (errorText == null) Expanded( child: SmoothSingleChildScrollView( - controller: scrollController, duration: const Duration(milliseconds: 100), stepSize: 40, child: Column( diff --git a/lib/widgets/misc/SmoothScrollBuilder.dart b/lib/widgets/misc/SmoothScrollBuilder.dart index f91cc6e1..4f1491b5 100644 --- a/lib/widgets/misc/SmoothScrollBuilder.dart +++ b/lib/widgets/misc/SmoothScrollBuilder.dart @@ -8,7 +8,7 @@ import '../../utils/utils.dart'; class SmoothScrollBuilder extends StatefulWidget { - final ScrollController controller; + final ScrollController? controller; final Duration duration; final double stepSize; final ScrollPhysics? physics; @@ -16,7 +16,7 @@ class SmoothScrollBuilder extends StatefulWidget { const SmoothScrollBuilder({ super.key, - required this.controller, + this.controller, required this.builder, this.duration = const Duration(milliseconds: 150), this.stepSize = 100, @@ -28,6 +28,7 @@ class SmoothScrollBuilder extends StatefulWidget { } class _SmoothScrollBuilderState extends State { + late ScrollController controller; static const ScrollPhysics desktopPhysics = NeverScrollableScrollPhysics(); static const ScrollPhysics? mobilePhysics = null; double targetOffset = 0; @@ -37,16 +38,26 @@ class _SmoothScrollBuilderState extends State { @override void initState() { - if (widget.controller.hasClients) - targetOffset = widget.controller.offset; - widget.controller.addListener(onScrollChange); + controller = widget.controller ?? ScrollController(); + if (controller.hasClients) + targetOffset = controller.offset; + controller.addListener(onScrollChange); super.initState(); } + @override + void dispose() { + controller.removeListener(onScrollChange); + isScrollingTimer?.cancel(); + if (widget.controller == null) + controller.dispose(); + super.dispose(); + } + void onScrollChange() { if (isScrolling) return; - targetOffset = widget.controller.offset; + targetOffset = controller.offset; } void onScrollEnd() { @@ -57,11 +68,11 @@ class _SmoothScrollBuilderState extends State { if (physics != desktopPhysics) setState(() => physics = desktopPhysics); targetOffset += widget.stepSize * event.scrollDelta.dy.sign; - targetOffset = clamp(targetOffset, 0, widget.controller.position.maxScrollExtent); - if (targetOffset == widget.controller.offset) + targetOffset = clamp(targetOffset, 0, controller.position.maxScrollExtent); + if (targetOffset == controller.offset) return; isScrolling = true; - widget.controller.animateTo(targetOffset, duration: widget.duration, curve: Curves.linear); + controller.animateTo(targetOffset, duration: widget.duration, curve: Curves.linear); isScrollingTimer?.cancel(); isScrollingTimer = Timer(widget.duration, onScrollEnd); } @@ -76,13 +87,13 @@ class _SmoothScrollBuilderState extends State { return Listener( onPointerSignal: (event) => event is PointerScrollEvent ? onWheelScroll(event) : null, onPointerDown: (_) => onContinuosScroll(), - child: widget.builder(context, widget.controller, physics), + child: widget.builder(context, controller, physics), ); } } class SmoothSingleChildScrollView extends StatelessWidget { - final ScrollController controller; + final ScrollController? controller; final Duration duration; final double stepSize; final ScrollPhysics? physics; @@ -91,7 +102,7 @@ class SmoothSingleChildScrollView extends StatelessWidget { const SmoothSingleChildScrollView({ super.key, - required this.controller, + this.controller, this.duration = const Duration(milliseconds: 150), this.stepSize = 100, this.physics, diff --git a/lib/widgets/misc/confirmDialog.dart b/lib/widgets/misc/confirmDialog.dart index 3e289c65..9ec2508e 100644 --- a/lib/widgets/misc/confirmDialog.dart +++ b/lib/widgets/misc/confirmDialog.dart @@ -9,7 +9,6 @@ import 'SmoothScrollBuilder.dart'; Future confirmDialog(BuildContext context, { required String title, String? body }) { var result = Completer(); - final ScrollController scrollController = ScrollController(); showDialog( context: context, builder: (context) => WillPopScope( @@ -25,7 +24,6 @@ Future confirmDialog(BuildContext context, { required String title, Strin child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 600, maxHeight: 450), child: SmoothSingleChildScrollView( - controller: scrollController, child: Column( mainAxisSize: MainAxisSize.min, crossAxisAlignment: CrossAxisAlignment.start, diff --git a/lib/widgets/misc/preferencesEditor.dart b/lib/widgets/misc/preferencesEditor.dart index 05ed727f..dcdee88a 100644 --- a/lib/widgets/misc/preferencesEditor.dart +++ b/lib/widgets/misc/preferencesEditor.dart @@ -28,12 +28,10 @@ class PreferencesEditor extends ChangeNotifierWidget { class _PreferencesEditorState extends ChangeNotifierState { static const sectionHeaderStyle = TextStyle(fontWeight: FontWeight.w300, fontSize: 18); - final controller = ScrollController(); @override Widget build(BuildContext context) { return SmoothSingleChildScrollView( - controller: controller, child: Padding( padding: const EdgeInsets.all(32), child: Column( diff --git a/lib/widgets/misc/selectionPopup.dart b/lib/widgets/misc/selectionPopup.dart index 11d31b06..122e6aa9 100644 --- a/lib/widgets/misc/selectionPopup.dart +++ b/lib/widgets/misc/selectionPopup.dart @@ -63,7 +63,6 @@ class _SelectionContextMenuState extends State<_SelectionContextMenu> with Arrow static const screenPadding = 10.0; final focusNode = TextFieldFocusNode(); - final scrollController = ScrollController(); String search = ""; @override @@ -85,12 +84,6 @@ class _SelectionContextMenuState extends State<_SelectionContextMenu> with Arrow Navigator.of(context).pop(); } - @override - void dispose() { - scrollController.dispose(); - super.dispose(); - } - @override Widget build(BuildContext context) { var searchedConfigs = widget.configs @@ -101,7 +94,6 @@ class _SelectionContextMenuState extends State<_SelectionContextMenu> with Arrow child: ConstrainedBox( constraints: const BoxConstraints(minWidth: popupWidth, maxWidth: popupWidth, maxHeight: maxPopupHeight), child: SmoothSingleChildScrollView( - controller: scrollController, child: Column( children: [ makeSearchBar(), diff --git a/lib/widgets/propEditors/textFieldAutocomplete.dart b/lib/widgets/propEditors/textFieldAutocomplete.dart index 824258d4..c153a8b8 100644 --- a/lib/widgets/propEditors/textFieldAutocomplete.dart +++ b/lib/widgets/propEditors/textFieldAutocomplete.dart @@ -175,6 +175,7 @@ class __AutocompleteOverlayState extends State<_AutocompleteOverlay> with ArrowN @override void dispose() { widget.textController.removeListener(_onTextChange); + scrollController.dispose(); super.dispose(); } diff --git a/lib/widgets/statusbar/messageLog.dart b/lib/widgets/statusbar/messageLog.dart index da6fc457..56eb15a1 100644 --- a/lib/widgets/statusbar/messageLog.dart +++ b/lib/widgets/statusbar/messageLog.dart @@ -98,6 +98,12 @@ class _MessageLogDialogState extends ChangeNotifierState<_MessageLogDialog> { jumpToEnd(); } + @override + void dispose() { + controller.dispose(); + super.dispose(); + } + void jumpToEnd() async { await waitForNextFrame(); controller.jumpTo(controller.position.maxScrollExtent); diff --git a/lib/widgets/tools/toolsOverview.dart b/lib/widgets/tools/toolsOverview.dart index b5ba26f6..91a5de23 100644 --- a/lib/widgets/tools/toolsOverview.dart +++ b/lib/widgets/tools/toolsOverview.dart @@ -13,13 +13,11 @@ class ToolsOverview extends StatefulWidget { } class _ToolsOverviewState extends State { - final scrollController = ScrollController(); final extractToolKey = const PageStorageKey("extractTool"); @override Widget build(BuildContext context) { return SmoothSingleChildScrollView( - controller: scrollController, child: Column( children: [ ExpansionTile( @@ -28,7 +26,7 @@ class _ToolsOverviewState extends State { initiallyExpanded: true, textColor: getTheme(context).textColor, maintainState: true, - children: [ + children: const [ ExtractFilesTool() ], )