diff --git a/lib/common/widgets/flutter/chat_list_view.dart b/lib/common/widgets/flutter/chat_list_view.dart index 45d8b38e4..540aaef0c 100644 --- a/lib/common/widgets/flutter/chat_list_view.dart +++ b/lib/common/widgets/flutter/chat_list_view.dart @@ -4,9 +4,8 @@ import 'dart:math' as math; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart' hide BoxScrollView; +import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; class ChatListView extends BoxScrollView { diff --git a/lib/common/widgets/flutter/scroll_view/scroll_view.dart b/lib/common/widgets/flutter/scroll_view/scroll_view.dart deleted file mode 100644 index 620b4cdc8..000000000 --- a/lib/common/widgets/flutter/scroll_view/scroll_view.dart +++ /dev/null @@ -1,2175 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:math' as math; - -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scrollable.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/widgets.dart' hide Scrollable; - -/// A widget that combines a [Scrollable] and a [Viewport] to create an -/// interactive scrolling pane of content in one dimension. -/// -/// Scrollable widgets consist of three pieces: -/// -/// 1. A [Scrollable] widget, which listens for various user gestures and -/// implements the interaction design for scrolling. -/// 2. A viewport widget, such as [Viewport] or [ShrinkWrappingViewport], which -/// implements the visual design for scrolling by displaying only a portion -/// of the widgets inside the scroll view. -/// 3. One or more slivers, which are widgets that can be composed to created -/// various scrolling effects, such as lists, grids, and expanding headers. -/// -/// [ScrollView] helps orchestrate these pieces by creating the [Scrollable] and -/// the viewport and deferring to its subclass to create the slivers. -/// -/// To learn more about slivers, see [ExtendedCustomScrollView.slivers]. -/// -/// To control the initial scroll offset of the scroll view, provide a -/// [controller] with its [ScrollController.initialScrollOffset] property set. -/// -/// {@template flutter.widgets.ScrollView.PageStorage} -/// ## Persisting the scroll position during a session -/// -/// Scroll views attempt to persist their scroll position using [PageStorage]. -/// This can be disabled by setting [ScrollController.keepScrollOffset] to false -/// on the [controller]. If it is enabled, using a [PageStorageKey] for the -/// [key] of this widget is recommended to help disambiguate different scroll -/// views from each other. -/// {@endtemplate} -/// -/// See also: -/// -/// * [ExtendedListView], which is a commonly used [ScrollView] that displays a -/// scrolling, linear list of child widgets. -/// * [PageView], which is a scrolling list of child widgets that are each the -/// size of the viewport. -/// * [ExtendedGridView], which is a [ScrollView] that displays a scrolling, 2D array -/// of child widgets. -/// * [ExtendedCustomScrollView], which is a [ScrollView] that creates custom scroll -/// effects using slivers. -/// * [ScrollNotification] and [NotificationListener], which can be used to watch -/// the scroll position without using a [ScrollController]. -/// * [TwoDimensionalScrollView], which is a similar widget [ScrollView] that -/// scrolls in two dimensions. -abstract class ScrollView extends StatelessWidget { - /// Creates a widget that scrolls. - /// - /// The [ScrollView.primary] argument defaults to true for vertical - /// scroll views if no [controller] has been provided. The [controller] argument - /// must be null if [primary] is explicitly set to true. If [primary] is true, - /// the nearest [PrimaryScrollController] surrounding the widget is attached - /// to this scroll view. - /// - /// If the [shrinkWrap] argument is true, the [center] argument must be null. - /// - /// The [anchor] argument must be in the range zero to one, inclusive. - const ScrollView({ - super.key, - this.scrollDirection = Axis.vertical, - this.reverse = false, - this.controller, - this.primary, - ScrollPhysics? physics, - this.scrollBehavior, - this.shrinkWrap = false, - this.center, - this.anchor = 0.0, - this.cacheExtent, - this.semanticChildCount, - this.paintOrder = SliverPaintOrder.firstIsTop, - this.dragStartBehavior = DragStartBehavior.start, - this.keyboardDismissBehavior, - this.restorationId, - this.clipBehavior = Clip.hardEdge, - this.hitTestBehavior = HitTestBehavior.opaque, - }) : assert( - !(controller != null && (primary ?? false)), - 'Primary ScrollViews obtain their ScrollController via inheritance ' - 'from a PrimaryScrollController widget. You cannot both set primary to ' - 'true and pass an explicit controller.', - ), - assert(!shrinkWrap || center == null), - assert(anchor >= 0.0 && anchor <= 1.0), - assert(semanticChildCount == null || semanticChildCount >= 0), - physics = - physics ?? - ((primary ?? false) || - (primary == null && - controller == null && - identical(scrollDirection, Axis.vertical)) - ? const AlwaysScrollableScrollPhysics() - : null); - - /// {@template flutter.widgets.scroll_view.scrollDirection} - /// The [Axis] along which the scroll view's offset increases. - /// - /// For the direction in which active scrolling may be occurring, see - /// [ScrollDirection]. - /// - /// Defaults to [Axis.vertical]. - /// {@endtemplate} - final Axis scrollDirection; - - /// {@template flutter.widgets.scroll_view.reverse} - /// Whether the scroll view scrolls in the reading direction. - /// - /// For example, if the reading direction is left-to-right and - /// [scrollDirection] is [Axis.horizontal], then the scroll view scrolls from - /// left to right when [reverse] is false and from right to left when - /// [reverse] is true. - /// - /// Similarly, if [scrollDirection] is [Axis.vertical], then the scroll view - /// scrolls from top to bottom when [reverse] is false and from bottom to top - /// when [reverse] is true. - /// - /// Defaults to false. - /// {@endtemplate} - final bool reverse; - - /// {@template flutter.widgets.scroll_view.controller} - /// An object that can be used to control the position to which this scroll - /// view is scrolled. - /// - /// Must be null if [primary] is true. - /// - /// A [ScrollController] serves several purposes. It can be used to control - /// the initial scroll position (see [ScrollController.initialScrollOffset]). - /// It can be used to control whether the scroll view should automatically - /// save and restore its scroll position in the [PageStorage] (see - /// [ScrollController.keepScrollOffset]). It can be used to read the current - /// scroll position (see [ScrollController.offset]), or change it (see - /// [ScrollController.animateTo]). - /// {@endtemplate} - final ScrollController? controller; - - /// {@template flutter.widgets.scroll_view.primary} - /// Whether this is the primary scroll view associated with the parent - /// [PrimaryScrollController]. - /// - /// When this is true, the scroll view is scrollable even if it does not have - /// sufficient content to actually scroll. Otherwise, by default the user can - /// only scroll the view if it has sufficient content. See [physics]. - /// - /// Also when true, the scroll view is used for default [ScrollAction]s. If a - /// ScrollAction is not handled by an otherwise focused part of the application, - /// the ScrollAction will be evaluated using this scroll view, for example, - /// when executing [Shortcuts] key events like page up and down. - /// - /// On iOS, this also identifies the scroll view that will scroll to top in - /// response to a tap in the status bar. - /// - /// Cannot be true while a [ScrollController] is provided to `controller`, - /// only one ScrollController can be associated with a ScrollView. - /// - /// Setting to false will explicitly prevent inheriting any - /// [PrimaryScrollController]. - /// - /// Defaults to null. When null, and a controller is not provided, - /// [PrimaryScrollController.shouldInherit] is used to decide automatic - /// inheritance. - /// - /// By default, the [PrimaryScrollController] that is injected by each - /// [ModalRoute] is configured to automatically be inherited on - /// [TargetPlatformVariant.mobile] for ScrollViews in the [Axis.vertical] - /// scroll direction. Adding another to your app will override the - /// PrimaryScrollController above it. - /// - /// The following video contains more information about scroll controllers, - /// the PrimaryScrollController widget, and their impact on your apps: - /// - /// {@youtube 560 315 https://www.youtube.com/watch?v=33_0ABjFJUU} - /// - /// {@endtemplate} - final bool? primary; - - /// {@template flutter.widgets.scroll_view.physics} - /// How the scroll view should respond to user input. - /// - /// For example, determines how the scroll view continues to animate after the - /// user stops dragging the scroll view. - /// - /// Defaults to matching platform conventions. Furthermore, if [primary] is - /// false, then the user cannot scroll if there is insufficient content to - /// scroll, while if [primary] is true, they can always attempt to scroll. - /// - /// To force the scroll view to always be scrollable even if there is - /// insufficient content, as if [primary] was true but without necessarily - /// setting it to true, provide an [AlwaysScrollableScrollPhysics] physics - /// object, as in: - /// - /// ```dart - /// physics: const AlwaysScrollableScrollPhysics(), - /// ``` - /// - /// To force the scroll view to use the default platform conventions and not - /// be scrollable if there is insufficient content, regardless of the value of - /// [primary], provide an explicit [ScrollPhysics] object, as in: - /// - /// ```dart - /// physics: const ScrollPhysics(), - /// ``` - /// - /// The physics can be changed dynamically (by providing a new object in a - /// subsequent build), but new physics will only take effect if the _class_ of - /// the provided object changes. Merely constructing a new instance with a - /// different configuration is insufficient to cause the physics to be - /// reapplied. (This is because the final object used is generated - /// dynamically, which can be relatively expensive, and it would be - /// inefficient to speculatively create this object each frame to see if the - /// physics should be updated.) - /// {@endtemplate} - /// - /// If an explicit [ScrollBehavior] is provided to [scrollBehavior], the - /// [ScrollPhysics] provided by that behavior will take precedence after - /// [physics]. - final ScrollPhysics? physics; - - /// {@macro flutter.widgets.scrollable.scrollBehavior} - final ScrollBehavior? scrollBehavior; - - /// {@template flutter.widgets.scroll_view.shrinkWrap} - /// Whether the extent of the scroll view in the [scrollDirection] should be - /// determined by the contents being viewed. - /// - /// If the scroll view does not shrink wrap, then the scroll view will expand - /// to the maximum allowed size in the [scrollDirection]. If the scroll view - /// has unbounded constraints in the [scrollDirection], then [shrinkWrap] must - /// be true. - /// - /// Shrink wrapping the content of the scroll view is significantly more - /// expensive than expanding to the maximum allowed size because the content - /// can expand and contract during scrolling, which means the size of the - /// scroll view needs to be recomputed whenever the scroll position changes. - /// - /// Defaults to false. - /// - /// {@youtube 560 315 https://www.youtube.com/watch?v=LUqDNnv_dh0} - /// {@endtemplate} - final bool shrinkWrap; - - /// The first child in the [GrowthDirection.forward] growth direction. - /// - /// Children after [center] will be placed in the [AxisDirection] determined - /// by [scrollDirection] and [reverse] relative to the [center]. Children - /// before [center] will be placed in the opposite of the axis direction - /// relative to the [center]. This makes the [center] the inflection point of - /// the growth direction. - /// - /// The [center] must be the key of one of the slivers built by [buildSlivers]. - /// - /// Of the built-in subclasses of [ScrollView], only [ExtendedCustomScrollView] - /// supports [center]; for that class, the given key must be the key of one of - /// the slivers in the [ExtendedCustomScrollView.slivers] list. - /// - /// Most scroll views by default are ordered [GrowthDirection.forward]. - /// Changing the default values of [ScrollView.anchor], - /// [ScrollView.center], or both, can configure a scroll view for - /// [GrowthDirection.reverse]. - /// - /// {@tool dartpad} - /// This sample shows a [ExtendedCustomScrollView], with [Radio] buttons in the - /// [AppBar.bottom] that change the [AxisDirection] to illustrate different - /// configurations. The [ExtendedCustomScrollView.anchor] and [ExtendedCustomScrollView.center] - /// properties are also set to have the 0 scroll offset positioned in the middle - /// of the viewport, with [GrowthDirection.forward] and [GrowthDirection.reverse] - /// illustrated on either side. The sliver that shares the - /// [ExtendedCustomScrollView.center] key is positioned at the [ExtendedCustomScrollView.anchor]. - /// - /// ** See code in examples/api/lib/rendering/growth_direction/growth_direction.0.dart ** - /// {@end-tool} - /// - /// See also: - /// - /// * [anchor], which controls where the [center] as aligned in the viewport. - final Key? center; - - /// {@template flutter.widgets.scroll_view.anchor} - /// The relative position of the zero scroll offset. - /// - /// For example, if [anchor] is 0.5 and the [AxisDirection] determined by - /// [scrollDirection] and [reverse] is [AxisDirection.down] or - /// [AxisDirection.up], then the zero scroll offset is vertically centered - /// within the viewport. If the [anchor] is 1.0, and the axis direction is - /// [AxisDirection.right], then the zero scroll offset is on the left edge of - /// the viewport. - /// - /// Most scroll views by default are ordered [GrowthDirection.forward]. - /// Changing the default values of [ScrollView.anchor], - /// [ScrollView.center], or both, can configure a scroll view for - /// [GrowthDirection.reverse]. - /// - /// {@tool dartpad} - /// This sample shows a [ExtendedCustomScrollView], with [Radio] buttons in the - /// [AppBar.bottom] that change the [AxisDirection] to illustrate different - /// configurations. The [ExtendedCustomScrollView.anchor] and [ExtendedCustomScrollView.center] - /// properties are also set to have the 0 scroll offset positioned in the middle - /// of the viewport, with [GrowthDirection.forward] and [GrowthDirection.reverse] - /// illustrated on either side. The sliver that shares the - /// [ExtendedCustomScrollView.center] key is positioned at the [ExtendedCustomScrollView.anchor]. - /// - /// ** See code in examples/api/lib/rendering/growth_direction/growth_direction.0.dart ** - /// {@end-tool} - /// {@endtemplate} - final double anchor; - - /// {@macro flutter.rendering.RenderViewportBase.cacheExtent} - final double? cacheExtent; - - /// The number of children that will contribute semantic information. - /// - /// Some subtypes of [ScrollView] can infer this value automatically. For - /// example [ExtendedListView] will use the number of widgets in the child list, - /// while the [ListView.separated] constructor will use half that amount. - /// - /// For [ExtendedCustomScrollView] and other types which do not receive a builder - /// or list of widgets, the child count must be explicitly provided. If the - /// number is unknown or unbounded this should be left unset or set to null. - /// - /// See also: - /// - /// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property. - final int? semanticChildCount; - - /// {@macro flutter.rendering.RenderViewportBase.paintOrder} - /// - /// Defaults to [SliverPaintOrder.firstIsTop]. - final SliverPaintOrder paintOrder; - - /// {@macro flutter.widgets.scrollable.dragStartBehavior} - final DragStartBehavior dragStartBehavior; - - /// {@template flutter.widgets.scroll_view.keyboardDismissBehavior} - /// The [ScrollViewKeyboardDismissBehavior] defines how this [ScrollView] will - /// dismiss the keyboard automatically. - /// {@endtemplate} - /// - /// If [keyboardDismissBehavior] is null then it will fallback to - /// [scrollBehavior]. If that is also null, the inherited - /// [ScrollBehavior.getKeyboardDismissBehavior] will be used. - final ScrollViewKeyboardDismissBehavior? keyboardDismissBehavior; - - /// {@macro flutter.widgets.scrollable.restorationId} - final String? restorationId; - - /// {@macro flutter.material.Material.clipBehavior} - /// - /// Defaults to [Clip.hardEdge]. - final Clip clipBehavior; - - /// {@macro flutter.widgets.scrollable.hitTestBehavior} - /// - /// Defaults to [HitTestBehavior.opaque]. - final HitTestBehavior hitTestBehavior; - - /// Returns the [AxisDirection] in which the scroll view scrolls. - /// - /// Combines the [scrollDirection] with the [reverse] boolean to obtain the - /// concrete [AxisDirection]. - /// - /// If the [scrollDirection] is [Axis.horizontal], the ambient - /// [Directionality] is also considered when selecting the concrete - /// [AxisDirection]. For example, if the ambient [Directionality] is - /// [TextDirection.rtl], then the non-reversed [AxisDirection] is - /// [AxisDirection.left] and the reversed [AxisDirection] is - /// [AxisDirection.right]. - @protected - AxisDirection getDirection(BuildContext context) { - return getAxisDirectionFromAxisReverseAndDirectionality( - context, - scrollDirection, - reverse, - ); - } - - /// Build the list of widgets to place inside the viewport. - /// - /// Subclasses should override this method to build the slivers for the inside - /// of the viewport. - /// - /// To learn more about slivers, see [ExtendedCustomScrollView.slivers]. - @protected - List buildSlivers(BuildContext context); - - /// Build the viewport. - /// - /// Subclasses may override this method to change how the viewport is built. - /// The default implementation uses a [ShrinkWrappingViewport] if [shrinkWrap] - /// is true, and a regular [Viewport] otherwise. - /// - /// The `offset` argument is the value obtained from - /// [Scrollable.viewportBuilder]. - /// - /// The `axisDirection` argument is the value obtained from [getDirection], - /// which by default uses [scrollDirection] and [reverse]. - /// - /// The `slivers` argument is the value obtained from [buildSlivers]. - @protected - Widget buildViewport( - BuildContext context, - ViewportOffset offset, - AxisDirection axisDirection, - List slivers, - ) { - assert(() { - switch (axisDirection) { - case AxisDirection.up: - case AxisDirection.down: - return debugCheckHasDirectionality( - context, - why: 'to determine the cross-axis direction of the scroll view', - hint: - 'Vertical scroll views create Viewport widgets that try to determine their cross axis direction ' - 'from the ambient Directionality.', - ); - case AxisDirection.left: - case AxisDirection.right: - return true; - } - }()); - if (shrinkWrap) { - return ShrinkWrappingViewport( - axisDirection: axisDirection, - offset: offset, - slivers: slivers, - paintOrder: paintOrder, - clipBehavior: clipBehavior, - ); - } - return Viewport( - axisDirection: axisDirection, - offset: offset, - slivers: slivers, - cacheExtent: cacheExtent, - center: center, - anchor: anchor, - paintOrder: paintOrder, - clipBehavior: clipBehavior, - ); - } - - @override - Widget build(BuildContext context) { - final List slivers = buildSlivers(context); - final AxisDirection axisDirection = getDirection(context); - - final bool effectivePrimary = - primary ?? - controller == null && - PrimaryScrollController.shouldInherit(context, scrollDirection); - - final ScrollController? scrollController = effectivePrimary - ? PrimaryScrollController.maybeOf(context) - : controller; - - final scrollable = Scrollable( - dragStartBehavior: dragStartBehavior, - axisDirection: axisDirection, - controller: scrollController, - physics: physics, - scrollBehavior: scrollBehavior, - semanticChildCount: semanticChildCount, - restorationId: restorationId, - hitTestBehavior: hitTestBehavior, - viewportBuilder: (BuildContext context, ViewportOffset offset) { - return buildViewport(context, offset, axisDirection, slivers); - }, - clipBehavior: clipBehavior, - ); - - final Widget scrollableResult = effectivePrimary && scrollController != null - // Further descendant ScrollViews will not inherit the same PrimaryScrollController - ? PrimaryScrollController.none(child: scrollable) - : scrollable; - - final ScrollViewKeyboardDismissBehavior effectiveKeyboardDismissBehavior = - keyboardDismissBehavior ?? - scrollBehavior?.getKeyboardDismissBehavior(context) ?? - ScrollConfiguration.of(context).getKeyboardDismissBehavior(context); - - if (effectiveKeyboardDismissBehavior == - ScrollViewKeyboardDismissBehavior.onDrag) { - return NotificationListener( - child: scrollableResult, - onNotification: (ScrollUpdateNotification notification) { - final FocusScopeNode currentScope = FocusScope.of(context); - if (notification.dragDetails != null && - !currentScope.hasPrimaryFocus && - currentScope.hasFocus) { - FocusManager.instance.primaryFocus?.unfocus(); - } - return false; - }, - ); - } else { - return scrollableResult; - } - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(EnumProperty('scrollDirection', scrollDirection)) - ..add( - FlagProperty( - 'reverse', - value: reverse, - ifTrue: 'reversed', - showName: true, - ), - ) - ..add( - DiagnosticsProperty( - 'controller', - controller, - showName: false, - defaultValue: null, - ), - ) - ..add( - FlagProperty( - 'primary', - value: primary, - ifTrue: 'using primary controller', - showName: true, - ), - ) - ..add( - DiagnosticsProperty( - 'physics', - physics, - showName: false, - defaultValue: null, - ), - ) - ..add( - FlagProperty( - 'shrinkWrap', - value: shrinkWrap, - ifTrue: 'shrink-wrapping', - showName: true, - ), - ); - } -} - -/// A [ScrollView] that creates custom scroll effects using [slivers]. -/// -/// A [ExtendedCustomScrollView] lets you supply [slivers] directly to create various -/// scrolling effects, such as lists, grids, and expanding headers. For example, -/// to create a scroll view that contains an expanding app bar followed by a -/// list and a grid, use a list of three slivers: [SliverAppBar], [SliverList], -/// and [SliverGrid]. -/// -/// [Widget]s in these [slivers] must produce [RenderSliver] objects. -/// -/// To control the initial scroll offset of the scroll view, provide a -/// [controller] with its [ScrollController.initialScrollOffset] property set. -/// -/// {@animation 400 376 https://flutter.github.io/assets-for-api-docs/assets/widgets/custom_scroll_view.mp4} -/// -/// {@tool snippet} -/// -/// This sample code shows a scroll view that contains a flexible pinned app -/// bar, a grid, and an infinite list. -/// -/// ```dart -/// CustomScrollView( -/// slivers: [ -/// const SliverAppBar( -/// pinned: true, -/// expandedHeight: 250.0, -/// flexibleSpace: FlexibleSpaceBar( -/// title: Text('Demo'), -/// ), -/// ), -/// SliverGrid( -/// gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent( -/// maxCrossAxisExtent: 200.0, -/// mainAxisSpacing: 10.0, -/// crossAxisSpacing: 10.0, -/// childAspectRatio: 4.0, -/// ), -/// delegate: SliverChildBuilderDelegate( -/// (BuildContext context, int index) { -/// return Container( -/// alignment: Alignment.center, -/// color: Colors.teal[100 * (index % 9)], -/// child: Text('Grid Item $index'), -/// ); -/// }, -/// childCount: 20, -/// ), -/// ), -/// SliverFixedExtentList( -/// itemExtent: 50.0, -/// delegate: SliverChildBuilderDelegate( -/// (BuildContext context, int index) { -/// return Container( -/// alignment: Alignment.center, -/// color: Colors.lightBlue[100 * (index % 9)], -/// child: Text('List Item $index'), -/// ); -/// }, -/// ), -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool dartpad} -/// By default, if items are inserted at the "top" of a scrolling container like -/// [ExtendedListView] or [ExtendedCustomScrollView], the top item and all of the items below it -/// are scrolled downwards. In some applications, it's preferable to have the -/// top of the list just grow upwards, without changing the scroll position. -/// This example demonstrates how to do that with a [ExtendedCustomScrollView] with -/// two [SliverList] children, and the [ExtendedCustomScrollView.center] set to the key -/// of the bottom SliverList. The top one SliverList will grow upwards, and the -/// bottom SliverList will grow downwards. -/// -/// ** See code in examples/api/lib/widgets/scroll_view/custom_scroll_view.1.dart ** -/// {@end-tool} -/// -/// ## Accessibility -/// -/// A [ExtendedCustomScrollView] can allow Talkback/VoiceOver to make announcements -/// to the user when the scroll state changes. For example, on Android an -/// announcement might be read as "showing items 1 to 10 of 23". To produce -/// this announcement, the scroll view needs three pieces of information: -/// -/// * The first visible child index. -/// * The total number of children. -/// * The total number of visible children. -/// -/// The last value can be computed exactly by the framework, however the first -/// two must be provided. Most of the higher-level scrollable widgets provide -/// this information automatically. For example, [ExtendedListView] provides each child -/// widget with a semantic index automatically and sets the semantic child -/// count to the length of the list. -/// -/// To determine visible indexes, the scroll view needs a way to associate the -/// generated semantics of each scrollable item with a semantic index. This can -/// be done by wrapping the child widgets in an [IndexedSemantics]. -/// -/// This semantic index is not necessarily the same as the index of the widget in -/// the scrollable, because some widgets may not contribute semantic -/// information. Consider a [ListView.separated]: every other widget is a -/// divider with no semantic information. In this case, only odd numbered -/// widgets have a semantic index (equal to the index ~/ 2). Furthermore, the -/// total number of children in this example would be half the number of -/// widgets. (The [ListView.separated] constructor handles this -/// automatically; this is only used here as an example.) -/// -/// The total number of visible children can be provided by the constructor -/// parameter `semanticChildCount`. This should always be the same as the -/// number of widgets wrapped in [IndexedSemantics]. -/// -/// {@macro flutter.widgets.ScrollView.PageStorage} -/// -/// See also: -/// -/// * [SliverList], which is a sliver that displays linear list of children. -/// * [SliverFixedExtentList], which is a more efficient sliver that displays -/// linear list of children that have the same extent along the scroll axis. -/// * [SliverGrid], which is a sliver that displays a 2D array of children. -/// * [SliverPadding], which is a sliver that adds blank space around another -/// sliver. -/// * [SliverAppBar], which is a sliver that displays a header that can expand -/// and float as the scroll view scrolls. -/// * [ScrollNotification] and [NotificationListener], which can be used to watch -/// the scroll position without using a [ScrollController]. -/// * [IndexedSemantics], which allows annotating child lists with an index -/// for scroll announcements. - -// ignore: camel_case_types -typedef customScrollView = ExtendedCustomScrollView; - -class ExtendedCustomScrollView extends ScrollView { - /// Creates a [ScrollView] that creates custom scroll effects using slivers. - /// - /// See the [ScrollView] constructor for more details on these arguments. - const ExtendedCustomScrollView({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.scrollBehavior, - super.shrinkWrap, - super.center, - super.anchor, - super.cacheExtent, - super.paintOrder, - this.slivers = const [], - super.semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }); - - /// The slivers to place inside the viewport. - /// - /// ## What is a sliver? - /// - /// > _**sliver** (noun): a small, thin piece of something._ - /// - /// A _sliver_ is a widget backed by a [RenderSliver] subclass, i.e. one that - /// implements the constraint/geometry protocol that uses [SliverConstraints] - /// and [SliverGeometry]. - /// - /// This is as distinct from those widgets that are backed by [RenderBox] - /// subclasses, which use [BoxConstraints] and [Size] respectively, and are - /// known as box widgets. (Widgets like [Container], [Row], and [SizedBox] are - /// box widgets.) - /// - /// While boxes are much more straightforward (implementing a simple - /// two-dimensional Cartesian layout system), slivers are much more powerful, - /// and are optimized for one-axis scrolling environments. - /// - /// Slivers are hosted in viewports, also known as scroll views, most notably - /// [ExtendedCustomScrollView]. - /// - /// ## Examples of slivers - /// - /// The Flutter framework has many built-in sliver widgets, and custom widgets - /// can be created in the same manner. By convention, sliver widgets always - /// start with the prefix `Sliver` and are always used in properties called - /// `sliver` or `slivers` (as opposed to `child` and `children` which are used - /// for box widgets). - /// - /// Examples of widgets unique to the sliver world include: - /// - /// * [SliverList], a lazily-loading list of variably-sized box widgets. - /// * [SliverFixedExtentList], a lazily-loading list of box widgets that are - /// all forced to the same height. - /// * [SliverPrototypeExtentList], a lazily-loading list of box widgets that - /// are all forced to the same height as a given prototype widget. - /// * [SliverGrid], a lazily-loading grid of box widgets. - /// * [SliverAnimatedList] and [SliverAnimatedGrid], animated variants of - /// [SliverList] and [SliverGrid]. - /// * [SliverFillRemaining], a widget that fills all remaining space in a - /// scroll view, and lays a box widget out inside that space. - /// * [SliverFillViewport], a widget that lays a list of boxes out, each - /// being sized to fit the whole viewport. - /// * [SliverPersistentHeader], a sliver that implements pinned and floating - /// headers, e.g. used to implement [SliverAppBar]. - /// * [SliverToBoxAdapter], a sliver that wraps a box widget. - /// - /// Examples of sliver variants of common box widgets include: - /// - /// * [SliverOpacity], [SliverAnimatedOpacity], and [SliverFadeTransition], - /// sliver versions of [Opacity], [AnimatedOpacity], and [FadeTransition]. - /// * [SliverIgnorePointer], a sliver version of [IgnorePointer]. - /// * [SliverLayoutBuilder], a sliver version of [LayoutBuilder]. - /// * [SliverOffstage], a sliver version of [Offstage]. - /// * [SliverPadding], a sliver version of [Padding]. - /// * [SliverReorderableList], a sliver version of [ReorderableList] - /// * [SliverSafeArea], a sliver version of [SafeArea]. - /// * [SliverVisibility], a sliver version of [Visibility]. - /// - /// ## Benefits of slivers over boxes - /// - /// The sliver protocol ([SliverConstraints] and [SliverGeometry]) enables - /// _scroll effects_, such as floating app bars, widgets that expand and - /// shrink during scroll, section headers that are pinned only while the - /// section's children are visible, etc. - /// - /// {@youtube 560 315 https://www.youtube.com/watch?v=Mz3kHQxBjGg} - /// - /// ## Mixing slivers and boxes - /// - /// In general, slivers always wrap box widgets to actually render anything - /// (for example, there is no sliver equivalent of [Text] or [Container]); - /// the sliver part of the equation is mostly about how these boxes should - /// be laid out in a viewport (i.e. when scrolling). - /// - /// Typically, the simplest way to combine boxes into a sliver environment is - /// to use a [SliverList] (maybe using a [ExtendedListView], which is a convenient - /// combination of a [ExtendedCustomScrollView] and a [SliverList]). In rare cases, - /// e.g. if a single [Divider] widget is needed between two [SliverGrid]s, - /// a [SliverToBoxAdapter] can be used to wrap the box widgets. - /// - /// ## Performance considerations - /// - /// Because the purpose of scroll views is to, well, scroll, it is common - /// for scroll views to contain more contents than are rendered on the screen - /// at any particular time. - /// - /// To improve the performance of scroll views, the content can be rendered in - /// _lazy_ widgets, notably [SliverList] and [SliverGrid] (and their variants, - /// such as [SliverFixedExtentList] and [SliverAnimatedGrid]). These widgets - /// ensure that only the portion of their child lists that are actually - /// visible get built, laid out, and painted. - /// - /// The [ExtendedListView] and [ExtendedGridView] widgets provide a convenient way to combine - /// a [ExtendedCustomScrollView] and a [SliverList] or [SliverGrid] (respectively). - final List slivers; - - @override - List buildSlivers(BuildContext context) => slivers; -} - -/// A [ScrollView] that uses a single child layout model. -/// -/// {@template flutter.widgets.BoxScroll.scrollBehaviour} -/// [ScrollView]s are often decorated with [Scrollbar]s and overscroll indicators, -/// which are managed by the inherited [ScrollBehavior]. Placing a -/// [ScrollConfiguration] above a ScrollView can modify these behaviors for that -/// ScrollView, or can be managed app-wide by providing a ScrollBehavior to -/// [MaterialApp.scrollBehavior] or [CupertinoApp.scrollBehavior]. -/// {@endtemplate} -/// -/// See also: -/// -/// * [ExtendedListView], which is a [BoxScrollView] that uses a linear layout model. -/// * [ExtendedGridView], which is a [BoxScrollView] that uses a 2D layout model. -/// * [ExtendedCustomScrollView], which can combine multiple child layout models into a -/// single scroll view. -abstract class BoxScrollView extends ScrollView { - /// Creates a [ScrollView] uses a single child layout model. - /// - /// If the [primary] argument is true, the [controller] must be null. - const BoxScrollView({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - this.padding, - super.cacheExtent, - super.semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }); - - /// The amount of space by which to inset the children. - final EdgeInsetsGeometry? padding; - - @override - List buildSlivers(BuildContext context) { - Widget sliver = buildChildLayout(context); - EdgeInsetsGeometry? effectivePadding = padding; - if (padding == null) { - final MediaQueryData? mediaQuery = MediaQuery.maybeOf(context); - if (mediaQuery != null) { - // Automatically pad sliver with padding from MediaQuery. - final EdgeInsets mediaQueryHorizontalPadding = mediaQuery.padding - .copyWith( - top: 0.0, - bottom: 0.0, - ); - final EdgeInsets mediaQueryVerticalPadding = mediaQuery.padding - .copyWith( - left: 0.0, - right: 0.0, - ); - // Consume the main axis padding with SliverPadding. - effectivePadding = scrollDirection == Axis.vertical - ? mediaQueryVerticalPadding - : mediaQueryHorizontalPadding; - // Leave behind the cross axis padding. - sliver = MediaQuery( - data: mediaQuery.copyWith( - padding: scrollDirection == Axis.vertical - ? mediaQueryHorizontalPadding - : mediaQueryVerticalPadding, - ), - child: sliver, - ); - } - } - - if (effectivePadding != null) { - sliver = SliverPadding(padding: effectivePadding, sliver: sliver); - } - return [sliver]; - } - - /// Subclasses should override this method to build the layout model. - @protected - Widget buildChildLayout(BuildContext context); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - DiagnosticsProperty( - 'padding', - padding, - defaultValue: null, - ), - ); - } -} - -/// A scrollable list of widgets arranged linearly. -/// -/// {@youtube 560 315 https://www.youtube.com/watch?v=KJpkjHGiI5A} -/// -/// [ExtendedListView] is the most commonly used scrolling widget. It displays its -/// children one after another in the scroll direction. In the cross axis, the -/// children are required to fill the [ExtendedListView]. -/// -/// If non-null, the [itemExtent] forces the children to have the given extent -/// in the scroll direction. -/// -/// If non-null, the [prototypeItem] forces the children to have the same extent -/// as the given widget in the scroll direction. -/// -/// Specifying an [itemExtent] or an [prototypeItem] is more efficient than -/// letting the children determine their own extent because the scrolling -/// machinery can make use of the foreknowledge of the children's extent to save -/// work, for example when the scroll position changes drastically. -/// -/// You can't specify both [itemExtent] and [prototypeItem], only one or none of -/// them. -/// -/// There are four options for constructing a [ExtendedListView]: -/// -/// 1. The default constructor takes an explicit [List] of children. This -/// constructor is appropriate for list views with a small number of -/// children because constructing the [List] requires doing work for every -/// child that could possibly be displayed in the list view instead of just -/// those children that are actually visible. -/// -/// 2. The [ListView.builder] constructor takes an [IndexedWidgetBuilder], which -/// builds the children on demand. This constructor is appropriate for list views -/// with a large (or infinite) number of children because the builder is called -/// only for those children that are actually visible. -/// -/// 3. The [ListView.separated] constructor takes two [IndexedWidgetBuilder]s: -/// `itemBuilder` builds child items on demand, and `separatorBuilder` -/// similarly builds separator children which appear in between the child items. -/// This constructor is appropriate for list views with a fixed number of children. -/// -/// 4. The [ListView.custom] constructor takes a [SliverChildDelegate], which provides -/// the ability to customize additional aspects of the child model. For example, -/// a [SliverChildDelegate] can control the algorithm used to estimate the -/// size of children that are not actually visible. -/// -/// To control the initial scroll offset of the scroll view, provide a -/// [controller] with its [ScrollController.initialScrollOffset] property set. -/// -/// By default, [ExtendedListView] will automatically pad the list's scrollable -/// extremities to avoid partial obstructions indicated by [MediaQuery]'s -/// padding. To avoid this behavior, override with a zero [padding] property. -/// -/// {@tool snippet} -/// This example uses the default constructor for [ExtendedListView] which takes an -/// explicit [List] of children. This [ExtendedListView]'s children are made up -/// of [Container]s with [Text]. -/// -/// ![A ListView of 3 amber colored containers with sample text.](https://flutter.github.io/assets-for-api-docs/assets/widgets/list_view.png) -/// -/// ```dart -/// ListView( -/// padding: const EdgeInsets.all(8), -/// children: [ -/// Container( -/// height: 50, -/// color: Colors.amber[600], -/// child: const Center(child: Text('Entry A')), -/// ), -/// Container( -/// height: 50, -/// color: Colors.amber[500], -/// child: const Center(child: Text('Entry B')), -/// ), -/// Container( -/// height: 50, -/// color: Colors.amber[100], -/// child: const Center(child: Text('Entry C')), -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool snippet} -/// This example mirrors the previous one, creating the same list using the -/// [ListView.builder] constructor. Using the [IndexedWidgetBuilder], children -/// are built lazily and can be infinite in number. -/// -/// ![A ListView of 3 amber colored containers with sample text.](https://flutter.github.io/assets-for-api-docs/assets/widgets/list_view_builder.png) -/// -/// ```dart -/// final List entries = ['A', 'B', 'C']; -/// final List colorCodes = [600, 500, 100]; -/// -/// Widget build(BuildContext context) { -/// return ListView.builder( -/// padding: const EdgeInsets.all(8), -/// itemCount: entries.length, -/// itemBuilder: (BuildContext context, int index) { -/// return Container( -/// height: 50, -/// color: Colors.amber[colorCodes[index]], -/// child: Center(child: Text('Entry ${entries[index]}')), -/// ); -/// } -/// ); -/// } -/// ``` -/// {@end-tool} -/// -/// {@tool snippet} -/// This example continues to build from our the previous ones, creating a -/// similar list using [ListView.separated]. Here, a [Divider] is used as a -/// separator. -/// -/// ![A ListView of 3 amber colored containers with sample text and a Divider -/// between each of them.](https://flutter.github.io/assets-for-api-docs/assets/widgets/list_view_separated.png) -/// -/// ```dart -/// final List entries = ['A', 'B', 'C']; -/// final List colorCodes = [600, 500, 100]; -/// -/// Widget build(BuildContext context) { -/// return ListView.separated( -/// padding: const EdgeInsets.all(8), -/// itemCount: entries.length, -/// itemBuilder: (BuildContext context, int index) { -/// return Container( -/// height: 50, -/// color: Colors.amber[colorCodes[index]], -/// child: Center(child: Text('Entry ${entries[index]}')), -/// ); -/// }, -/// separatorBuilder: (BuildContext context, int index) => const Divider(), -/// ); -/// } -/// ``` -/// {@end-tool} -/// -/// ## Child elements' lifecycle -/// -/// ### Creation -/// -/// While laying out the list, visible children's elements, states and render -/// objects will be created lazily based on existing widgets (such as when using -/// the default constructor) or lazily provided ones (such as when using the -/// [ListView.builder] constructor). -/// -/// ### Destruction -/// -/// When a child is scrolled out of view, the associated element subtree, -/// states and render objects are destroyed. A new child at the same position -/// in the list will be lazily recreated along with new elements, states and -/// render objects when it is scrolled back. -/// -/// ### Destruction mitigation -/// -/// In order to preserve state as child elements are scrolled in and out of -/// view, the following options are possible: -/// -/// * Moving the ownership of non-trivial UI-state-driving business logic -/// out of the list child subtree. For instance, if a list contains posts -/// with their number of upvotes coming from a cached network response, store -/// the list of posts and upvote number in a data model outside the list. Let -/// the list child UI subtree be easily recreate-able from the -/// source-of-truth model object. Use [StatefulWidget]s in the child -/// widget subtree to store instantaneous UI state only. -/// -/// * Letting [KeepAlive] be the root widget of the list child widget subtree -/// that needs to be preserved. The [KeepAlive] widget marks the child -/// subtree's top render object child for keepalive. When the associated top -/// render object is scrolled out of view, the list keeps the child's render -/// object (and by extension, its associated elements and states) in a cache -/// list instead of destroying them. When scrolled back into view, the render -/// object is repainted as-is (if it wasn't marked dirty in the interim). -/// -/// This only works if `addAutomaticKeepAlives` and `addRepaintBoundaries` -/// are false since those parameters cause the [ListView] to wrap each child -/// widget subtree with other widgets. -/// -/// * Using [AutomaticKeepAlive] widgets (inserted by default when -/// `addAutomaticKeepAlives` is true). [AutomaticKeepAlive] allows descendant -/// widgets to control whether the subtree is actually kept alive or not. -/// This behavior is in contrast with [KeepAlive], which will unconditionally keep -/// the subtree alive. -/// -/// As an example, the [EditableText] widget signals its list child element -/// subtree to stay alive while its text field has input focus. If it doesn't -/// have focus and no other descendants signaled for keepalive via a -/// [KeepAliveNotification], the list child element subtree will be destroyed -/// when scrolled away. -/// -/// [AutomaticKeepAlive] descendants typically signal it to be kept alive -/// by using the [AutomaticKeepAliveClientMixin], then implementing the -/// [AutomaticKeepAliveClientMixin.wantKeepAlive] getter and calling -/// [AutomaticKeepAliveClientMixin.updateKeepAlive]. -/// -/// ## Transitioning to [ExtendedCustomScrollView] -/// -/// A [ExtendedListView] is basically a [ExtendedCustomScrollView] with a single [SliverList] in -/// its [ExtendedCustomScrollView.slivers] property. -/// -/// If [ExtendedListView] is no longer sufficient, for example because the scroll view -/// is to have both a list and a grid, or because the list is to be combined -/// with a [SliverAppBar], etc, it is straight-forward to port code from using -/// [ExtendedListView] to using [ExtendedCustomScrollView] directly. -/// -/// The [key], [scrollDirection], [reverse], [controller], [primary], [physics], -/// and [shrinkWrap] properties on [ExtendedListView] map directly to the identically -/// named properties on [ExtendedCustomScrollView]. -/// -/// The [ExtendedCustomScrollView.slivers] property should be a list containing either: -/// * a [SliverList] if both [itemExtent] and [prototypeItem] were null; -/// * a [SliverFixedExtentList] if [itemExtent] was not null; or -/// * a [SliverPrototypeExtentList] if [prototypeItem] was not null. -/// -/// The [childrenDelegate] property on [ExtendedListView] corresponds to the -/// [SliverList.delegate] (or [SliverFixedExtentList.delegate]) property. The -/// [ExtendedListView] constructor's `children` argument corresponds to the -/// [childrenDelegate] being a [SliverChildListDelegate] with that same -/// argument. The [ListView.builder] constructor's `itemBuilder` and -/// `itemCount` arguments correspond to the [childrenDelegate] being a -/// [SliverChildBuilderDelegate] with the equivalent arguments. -/// -/// The [padding] property corresponds to having a [SliverPadding] in the -/// [ExtendedCustomScrollView.slivers] property instead of the list itself, and having -/// the [SliverList] instead be a child of the [SliverPadding]. -/// -/// [ExtendedCustomScrollView]s don't automatically avoid obstructions from [MediaQuery] -/// like [ExtendedListView]s do. To reproduce the behavior, wrap the slivers in -/// [SliverSafeArea]s. -/// -/// Once code has been ported to use [ExtendedCustomScrollView], other slivers, such as -/// [SliverGrid] or [SliverAppBar], can be put in the [ExtendedCustomScrollView.slivers] -/// list. -/// -/// {@tool snippet} -/// -/// Here are two brief snippets showing a [ExtendedListView] and its equivalent using -/// [CustomScrollView]: -/// -/// ```dart -/// ListView( -/// padding: const EdgeInsets.all(20.0), -/// children: const [ -/// Text("I'm dedicating every day to you"), -/// Text('Domestic life was never quite my style'), -/// Text('When you smile, you knock me out, I fall apart'), -/// Text('And I thought I was so smart'), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// {@tool snippet} -/// -/// ```dart -/// CustomScrollView( -/// slivers: [ -/// SliverPadding( -/// padding: const EdgeInsets.all(20.0), -/// sliver: SliverList( -/// delegate: SliverChildListDelegate( -/// [ -/// const Text("I'm dedicating every day to you"), -/// const Text('Domestic life was never quite my style'), -/// const Text('When you smile, you knock me out, I fall apart'), -/// const Text('And I thought I was so smart'), -/// ], -/// ), -/// ), -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// ## Special handling for an empty list -/// -/// A common design pattern is to have a custom UI for an empty list. The best -/// way to achieve this in Flutter is just conditionally replacing the -/// [ExtendedListView] at build time with whatever widgets you need to show for the -/// empty list state: -/// -/// {@tool snippet} -/// -/// Example of simple empty list interface: -/// -/// ```dart -/// Widget build(BuildContext context) { -/// return Scaffold( -/// appBar: AppBar(title: const Text('Empty List Test')), -/// body: itemCount > 0 -/// ? ListView.builder( -/// itemCount: itemCount, -/// itemBuilder: (BuildContext context, int index) { -/// return ListTile( -/// title: Text('Item ${index + 1}'), -/// ); -/// }, -/// ) -/// : const Center(child: Text('No items')), -/// ); -/// } -/// ``` -/// {@end-tool} -/// -/// ## Selection of list items -/// -/// [ExtendedListView] has no built-in notion of a selected item or items. For a small -/// example of how a caller might wire up basic item selection, see -/// [ListTile.selected]. -/// -/// {@tool dartpad} -/// This example shows a custom implementation of [ListTile] selection in a [ExtendedListView] or [ExtendedGridView]. -/// Long press any [ListTile] to enable selection mode. -/// -/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart ** -/// {@end-tool} -/// -/// {@macro flutter.widgets.BoxScroll.scrollBehaviour} -/// -/// {@macro flutter.widgets.ScrollView.PageStorage} -/// -/// See also: -/// -/// * [SingleChildScrollView], which is a scrollable widget that has a single -/// child. -/// * [PageView], which is a scrolling list of child widgets that are each the -/// size of the viewport. -/// * [ExtendedGridView], which is a scrollable, 2D array of widgets. -/// * [ExtendedCustomScrollView], which is a scrollable widget that creates custom -/// scroll effects using slivers. -/// * [ListBody], which arranges its children in a similar manner, but without -/// scrolling. -/// * [ScrollNotification] and [NotificationListener], which can be used to watch -/// the scroll position without using a [ScrollController]. -/// * The [catalog of layout widgets](https://docs.flutter.dev/ui/widgets/layout). -/// * Cookbook: [Use lists](https://docs.flutter.dev/cookbook/lists/basic-list) -/// * Cookbook: [Work with long lists](https://docs.flutter.dev/cookbook/lists/long-lists) -/// * Cookbook: [Create a horizontal list](https://docs.flutter.dev/cookbook/lists/horizontal-list) -/// * Cookbook: [Create lists with different types of items](https://docs.flutter.dev/cookbook/lists/mixed-list) -/// * Cookbook: [Implement swipe to dismiss](https://docs.flutter.dev/cookbook/gestures/dismissible) -// ignore: camel_case_types -typedef listView = ExtendedListView; - -class ExtendedListView extends BoxScrollView { - /// Creates a scrollable, linear array of widgets from an explicit [List]. - /// - /// This constructor is appropriate for list views with a small number of - /// children because constructing the [List] requires doing work for every - /// child that could possibly be displayed in the list view instead of just - /// those children that are actually visible. - /// - /// Like other widgets in the framework, this widget expects that - /// the [children] list will not be mutated after it has been passed in here. - /// See the documentation at [SliverChildListDelegate.children] for more details. - /// - /// It is usually more efficient to create children on demand using - /// [ListView.builder] because it will create the widget children lazily as necessary. - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildListDelegate.addRepaintBoundaries] property. The - /// `addSemanticIndexes` argument corresponds to the - /// [SliverChildListDelegate.addSemanticIndexes] property. None - /// may be null. - ExtendedListView({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - this.itemExtent, - this.itemExtentBuilder, - this.prototypeItem, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - List children = const [], - int? semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : assert( - (itemExtent == null && prototypeItem == null) || - (itemExtent == null && itemExtentBuilder == null) || - (prototypeItem == null && itemExtentBuilder == null), - 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', - ), - childrenDelegate = SliverChildListDelegate( - children, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? children.length); - - /// Creates a scrollable, linear array of widgets that are created on demand. - /// - /// This constructor is appropriate for list views with a large (or infinite) - /// number of children because the builder is called only for those children - /// that are actually visible. - /// - /// Providing a non-null `itemCount` improves the ability of the [ExtendedListView] to - /// estimate the maximum scroll extent. - /// - /// The `itemBuilder` callback will be called only with indices greater than - /// or equal to zero and less than `itemCount`. - /// - /// {@template flutter.widgets.ListView.builder.itemBuilder} - /// It is legal for `itemBuilder` to return `null`. If it does, the scroll view - /// will stop calling `itemBuilder`, even if it has yet to reach `itemCount`. - /// By returning `null`, the [ScrollPosition.maxScrollExtent] will not be accurate - /// unless the user has reached the end of the [ScrollView]. This can also cause the - /// [Scrollbar] to grow as the user scrolls. - /// - /// For more accurate [ScrollMetrics], consider specifying `itemCount`. - /// {@endtemplate} - /// - /// The `itemBuilder` should always create the widget instances when called. - /// Avoid using a builder that returns a previously-constructed widget; if the - /// list view's children are created in advance, or all at once when the - /// [ExtendedListView] itself is created, it is more efficient to use the [ExtendedListView] - /// constructor. Even more efficient, however, is to create the instances on - /// demand using this constructor's `itemBuilder` callback. - /// - /// {@macro flutter.widgets.PageView.findChildIndexCallback} - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The - /// `addSemanticIndexes` argument corresponds to the - /// [SliverChildBuilderDelegate.addSemanticIndexes] property. None may be - /// null. - ExtendedListView.builder({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - this.itemExtent, - this.itemExtentBuilder, - this.prototypeItem, - required NullableIndexedWidgetBuilder itemBuilder, - ChildIndexGetter? findChildIndexCallback, - int? itemCount, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - int? semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : assert(itemCount == null || itemCount >= 0), - assert(semanticChildCount == null || semanticChildCount <= itemCount!), - assert( - (itemExtent == null && prototypeItem == null) || - (itemExtent == null && itemExtentBuilder == null) || - (prototypeItem == null && itemExtentBuilder == null), - 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', - ), - childrenDelegate = SliverChildBuilderDelegate( - itemBuilder, - findChildIndexCallback: findChildIndexCallback, - childCount: itemCount, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? itemCount); - - /// Creates a fixed-length scrollable linear array of list "items" separated - /// by list item "separators". - /// - /// This constructor is appropriate for list views with a large number of - /// item and separator children because the builders are only called for - /// the children that are actually visible. - /// - /// The `itemBuilder` callback will be called with indices greater than - /// or equal to zero and less than `itemCount`. - /// - /// Separators only appear between list items: separator 0 appears after item - /// 0 and the last separator appears before the last item. - /// - /// The `separatorBuilder` callback will be called with indices greater than - /// or equal to zero and less than `itemCount - 1`. - /// - /// The `itemBuilder` and `separatorBuilder` callbacks should always - /// actually create widget instances when called. Avoid using a builder that - /// returns a previously-constructed widget; if the list view's children are - /// created in advance, or all at once when the [ExtendedListView] itself is created, - /// it is more efficient to use the [ExtendedListView] constructor. - /// - /// {@macro flutter.widgets.ListView.builder.itemBuilder} - /// - /// {@macro flutter.widgets.PageView.findChildIndexCallback} - /// - /// {@template flutter.widgets.ListView.separated.findItemIndexCallback} - /// The [findItemIndexCallback] returns item indices (excluding separators), - /// unlike the deprecated [findChildIndexCallback] which returns child indices - /// (including both items and separators). - /// - /// For example, in a list with 3 items and 2 separators: - /// * Item indices: 0, 1, 2 - /// * Child indices: 0 (item), 1 (separator), 2 (item), 3 (separator), 4 (item) - /// - /// This callback should be implemented if the order of items may change at a - /// later time. If null, reordering items may result in state-loss as widgets - /// may not map to their existing [RenderObject]s. - /// {@endtemplate} - /// - /// {@tool snippet} - /// - /// This example shows how to create [ExtendedListView] whose [ListTile] list items - /// are separated by [Divider]s. - /// - /// ```dart - /// ListView.separated( - /// itemCount: 25, - /// separatorBuilder: (BuildContext context, int index) => const Divider(), - /// itemBuilder: (BuildContext context, int index) { - /// return ListTile( - /// title: Text('item $index'), - /// ); - /// }, - /// ) - /// ``` - /// {@end-tool} - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The - /// `addSemanticIndexes` argument corresponds to the - /// [SliverChildBuilderDelegate.addSemanticIndexes] property. None may be - /// null. - ExtendedListView.separated({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required NullableIndexedWidgetBuilder itemBuilder, - @Deprecated( - 'Use findItemIndexCallback instead. ' - 'findChildIndexCallback returns child indices (which include separators), ' - 'while findItemIndexCallback returns item indices (which do not). ' - 'If you were multiplying results by 2 to account for separators, ' - 'you can remove that workaround when migrating to findItemIndexCallback. ' - 'This feature was deprecated after v3.37.0-1.0.pre.', - ) - ChildIndexGetter? findChildIndexCallback, - ChildIndexGetter? findItemIndexCallback, - required IndexedWidgetBuilder separatorBuilder, - required int itemCount, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : assert(itemCount >= 0), - assert( - findItemIndexCallback == null || findChildIndexCallback == null, - 'Cannot provide both findItemIndexCallback and findChildIndexCallback. ' - 'Use findItemIndexCallback as findChildIndexCallback is deprecated.', - ), - itemExtent = null, - itemExtentBuilder = null, - prototypeItem = null, - childrenDelegate = SliverChildBuilderDelegate( - (BuildContext context, int index) { - final int itemIndex = index ~/ 2; - if (index.isEven) { - return itemBuilder(context, itemIndex); - } - return separatorBuilder(context, itemIndex); - }, - findChildIndexCallback: findItemIndexCallback != null - ? (Key key) { - final int? itemIndex = findItemIndexCallback(key); - return itemIndex == null ? null : itemIndex * 2; - } - : findChildIndexCallback, - childCount: _computeActualChildCount(itemCount), - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - semanticIndexCallback: (Widget widget, int index) { - return index.isEven ? index ~/ 2 : null; - }, - ), - super(semanticChildCount: itemCount); - - /// Creates a scrollable, linear array of widgets with a custom child model. - /// - /// For example, a custom child model can control the algorithm used to - /// estimate the size of children that are not actually visible. - /// - /// {@tool dartpad} - /// This example shows a [ExtendedListView] that uses a custom [SliverChildBuilderDelegate] to support child - /// reordering. - /// - /// ** See code in examples/api/lib/widgets/scroll_view/list_view.1.dart ** - /// {@end-tool} - const ExtendedListView.custom({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - this.itemExtent, - this.prototypeItem, - this.itemExtentBuilder, - required this.childrenDelegate, - super.cacheExtent, - super.semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : assert( - (itemExtent == null && prototypeItem == null) || - (itemExtent == null && itemExtentBuilder == null) || - (prototypeItem == null && itemExtentBuilder == null), - 'You can only pass one of itemExtent, prototypeItem and itemExtentBuilder.', - ); - - /// {@template flutter.widgets.list_view.itemExtent} - /// If non-null, forces the children to have the given extent in the scroll - /// direction. - /// - /// Specifying an [itemExtent] is more efficient than letting the children - /// determine their own extent because the scrolling machinery can make use of - /// the foreknowledge of the children's extent to save work, for example when - /// the scroll position changes drastically. - /// - /// See also: - /// - /// * [SliverFixedExtentList], the sliver used internally when this property - /// is provided. It constrains its box children to have a specific given - /// extent along the main axis. - /// * The [prototypeItem] property, which allows forcing the children's - /// extent to be the same as the given widget. - /// * The [itemExtentBuilder] property, which allows forcing the children's - /// extent to be the value returned by the callback. - /// {@endtemplate} - final double? itemExtent; - - /// {@template flutter.widgets.list_view.itemExtentBuilder} - /// If non-null, forces the children to have the corresponding extent returned - /// by the builder. - /// - /// Specifying an [itemExtentBuilder] is more efficient than letting the children - /// determine their own extent because the scrolling machinery can make use of - /// the foreknowledge of the children's extent to save work, for example when - /// the scroll position changes drastically. - /// - /// This will be called multiple times during the layout phase of a frame to find - /// the items that should be loaded by the lazy loading process. - /// - /// Should return null if asked to build an item extent with a greater index than - /// exists. - /// - /// Unlike [itemExtent] or [prototypeItem], this allows children to have - /// different extents. - /// - /// See also: - /// - /// * [SliverVariedExtentList], the sliver used internally when this property - /// is provided. It constrains its box children to have a specific given - /// extent along the main axis. - /// * The [itemExtent] property, which allows forcing the children's extent - /// to a given value. - /// * The [prototypeItem] property, which allows forcing the children's - /// extent to be the same as the given widget. - /// {@endtemplate} - final ItemExtentBuilder? itemExtentBuilder; - - /// {@template flutter.widgets.list_view.prototypeItem} - /// If non-null, forces the children to have the same extent as the given - /// widget in the scroll direction. - /// - /// Specifying an [prototypeItem] is more efficient than letting the children - /// determine their own extent because the scrolling machinery can make use of - /// the foreknowledge of the children's extent to save work, for example when - /// the scroll position changes drastically. - /// - /// See also: - /// - /// * [SliverPrototypeExtentList], the sliver used internally when this - /// property is provided. It constrains its box children to have the same - /// extent as a prototype item along the main axis. - /// * The [itemExtent] property, which allows forcing the children's extent - /// to a given value. - /// * The [itemExtentBuilder] property, which allows forcing the children's - /// extent to be the value returned by the callback. - /// {@endtemplate} - final Widget? prototypeItem; - - /// A delegate that provides the children for the [ExtendedListView]. - /// - /// The [ListView.custom] constructor lets you specify this delegate - /// explicitly. The [ExtendedListView] and [ListView.builder] constructors create a - /// [childrenDelegate] that wraps the given [List] and [IndexedWidgetBuilder], - /// respectively. - final SliverChildDelegate childrenDelegate; - - @override - Widget buildChildLayout(BuildContext context) { - if (itemExtent != null) { - return SliverFixedExtentList( - delegate: childrenDelegate, - itemExtent: itemExtent!, - ); - } else if (itemExtentBuilder != null) { - return SliverVariedExtentList( - delegate: childrenDelegate, - itemExtentBuilder: itemExtentBuilder!, - ); - } else if (prototypeItem != null) { - return SliverPrototypeExtentList( - delegate: childrenDelegate, - prototypeItem: prototypeItem!, - ); - } - return SliverList(delegate: childrenDelegate); - } - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties.add( - DoubleProperty('itemExtent', itemExtent, defaultValue: null), - ); - } - - // Helper method to compute the actual child count for the separated constructor. - static int _computeActualChildCount(int itemCount) { - return math.max(0, itemCount * 2 - 1); - } -} - -/// A scrollable, 2D array of widgets. -/// -/// {@youtube 560 315 https://www.youtube.com/watch?v=bLOtZDTm4H8} -/// -/// The main axis direction of a grid is the direction in which it scrolls (the -/// [scrollDirection]). -/// -/// The most commonly used grid layouts are [GridView.count], which creates a -/// layout with a fixed number of tiles in the cross axis, and -/// [GridView.extent], which creates a layout with tiles that have a maximum -/// cross-axis extent. A custom [SliverGridDelegate] can produce an arbitrary 2D -/// arrangement of children, including arrangements that are unaligned or -/// overlapping. -/// -/// To create a grid with a large (or infinite) number of children, use the -/// [GridView.builder] constructor with either a -/// [SliverGridDelegateWithFixedCrossAxisCount] or a -/// [SliverGridDelegateWithMaxCrossAxisExtent] for the [gridDelegate]. -/// -/// To use a custom [SliverChildDelegate], use [GridView.custom]. -/// -/// To create a linear array of children, use a [ExtendedListView]. -/// -/// To control the initial scroll offset of the scroll view, provide a -/// [controller] with its [ScrollController.initialScrollOffset] property set. -/// -/// ## Transitioning to [ExtendedCustomScrollView] -/// -/// A [ExtendedGridView] is basically a [ExtendedCustomScrollView] with a single [SliverGrid] in -/// its [ExtendedCustomScrollView.slivers] property. -/// -/// If [ExtendedGridView] is no longer sufficient, for example because the scroll view -/// is to have both a grid and a list, or because the grid is to be combined -/// with a [SliverAppBar], etc, it is straight-forward to port code from using -/// [ExtendedGridView] to using [ExtendedCustomScrollView] directly. -/// -/// The [key], [scrollDirection], [reverse], [controller], [primary], [physics], -/// and [shrinkWrap] properties on [ExtendedGridView] map directly to the identically -/// named properties on [ExtendedCustomScrollView]. -/// -/// The [ExtendedCustomScrollView.slivers] property should be a list containing just a -/// [SliverGrid]. -/// -/// The [childrenDelegate] property on [ExtendedGridView] corresponds to the -/// [SliverGrid.delegate] property, and the [gridDelegate] property on the -/// [ExtendedGridView] corresponds to the [SliverGrid.gridDelegate] property. -/// -/// The [ExtendedGridView], [GridView.count], and [GridView.extent] -/// constructors' `children` arguments correspond to the [childrenDelegate] -/// being a [SliverChildListDelegate] with that same argument. The -/// [GridView.builder] constructor's `itemBuilder` and `childCount` arguments -/// correspond to the [childrenDelegate] being a [SliverChildBuilderDelegate] -/// with the matching arguments. -/// -/// The [GridView.count] and [GridView.extent] constructors create -/// custom grid delegates, and have equivalently named constructors on -/// [SliverGrid] to ease the transition: [SliverGrid.count] and -/// [SliverGrid.extent] respectively. -/// -/// The [padding] property corresponds to having a [SliverPadding] in the -/// [ExtendedCustomScrollView.slivers] property instead of the grid itself, and having -/// the [SliverGrid] instead be a child of the [SliverPadding]. -/// -/// Once code has been ported to use [ExtendedCustomScrollView], other slivers, such as -/// [SliverList] or [SliverAppBar], can be put in the [ExtendedCustomScrollView.slivers] -/// list. -/// -/// {@macro flutter.widgets.ScrollView.PageStorage} -/// -/// ## Examples -/// -/// {@tool snippet} -/// This example demonstrates how to create a [ExtendedGridView] with two columns. The -/// children are spaced apart using the `crossAxisSpacing` and `mainAxisSpacing` -/// properties. -/// -/// ![The GridView displays six children with different background colors arranged in two columns](https://flutter.github.io/assets-for-api-docs/assets/widgets/grid_view.png) -/// -/// ```dart -/// GridView.count( -/// primary: false, -/// padding: const EdgeInsets.all(20), -/// crossAxisSpacing: 10, -/// mainAxisSpacing: 10, -/// crossAxisCount: 2, -/// children: [ -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[100], -/// child: const Text("He'd have you all unravel at the"), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[200], -/// child: const Text('Heed not the rabble'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[300], -/// child: const Text('Sound of screams but the'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[400], -/// child: const Text('Who scream'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[500], -/// child: const Text('Revolution is coming...'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.teal[600], -/// child: const Text('Revolution, they...'), -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool snippet} -/// This example shows how to create the same grid as the previous example -/// using a [ExtendedCustomScrollView] and a [SliverGrid]. -/// -/// ![The CustomScrollView contains a SliverGrid that displays six children with different background colors arranged in two columns](https://flutter.github.io/assets-for-api-docs/assets/widgets/grid_view_custom_scroll.png) -/// -/// ```dart -/// CustomScrollView( -/// primary: false, -/// slivers: [ -/// SliverPadding( -/// padding: const EdgeInsets.all(20), -/// sliver: SliverGrid.count( -/// crossAxisSpacing: 10, -/// mainAxisSpacing: 10, -/// crossAxisCount: 2, -/// children: [ -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[100], -/// child: const Text("He'd have you all unravel at the"), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[200], -/// child: const Text('Heed not the rabble'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[300], -/// child: const Text('Sound of screams but the'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[400], -/// child: const Text('Who scream'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[500], -/// child: const Text('Revolution is coming...'), -/// ), -/// Container( -/// padding: const EdgeInsets.all(8), -/// color: Colors.green[600], -/// child: const Text('Revolution, they...'), -/// ), -/// ], -/// ), -/// ), -/// ], -/// ) -/// ``` -/// {@end-tool} -/// -/// {@tool dartpad} -/// This example shows a custom implementation of selection in list and grid views. -/// Use the button in the top right (possibly hidden under the DEBUG banner) to toggle between -/// [ExtendedListView] and [ExtendedGridView]. -/// Long press any [ListTile] or [GridTile] to enable selection mode. -/// -/// ** See code in examples/api/lib/widgets/scroll_view/list_view.0.dart ** -/// {@end-tool} -/// -/// {@tool dartpad} -/// This example shows a custom [SliverGridDelegate]. -/// -/// ** See code in examples/api/lib/widgets/scroll_view/grid_view.0.dart ** -/// {@end-tool} -/// -/// ## Troubleshooting -/// -/// ### Padding -/// -/// By default, [ExtendedGridView] will automatically pad the limits of the -/// grid's scrollable to avoid partial obstructions indicated by -/// [MediaQuery]'s padding. To avoid this behavior, override with a -/// zero [padding] property. -/// -/// {@tool snippet} -/// The following example demonstrates how to override the default top padding -/// using [MediaQuery.removePadding]. -/// -/// ```dart -/// Widget myWidget(BuildContext context) { -/// return MediaQuery.removePadding( -/// context: context, -/// removeTop: true, -/// child: GridView.builder( -/// gridDelegate: const SliverGridDelegateWithFixedCrossAxisCount( -/// crossAxisCount: 3, -/// ), -/// itemCount: 300, -/// itemBuilder: (BuildContext context, int index) { -/// return Card( -/// color: Colors.amber, -/// child: Center(child: Text('$index')), -/// ); -/// } -/// ), -/// ); -/// } -/// ``` -/// {@end-tool} -/// -/// See also: -/// -/// * [SingleChildScrollView], which is a scrollable widget that has a single -/// child. -/// * [ExtendedListView], which is scrollable, linear list of widgets. -/// * [PageView], which is a scrolling list of child widgets that are each the -/// size of the viewport. -/// * [ExtendedCustomScrollView], which is a scrollable widget that creates custom -/// scroll effects using slivers. -/// * [SliverGridDelegateWithFixedCrossAxisCount], which creates a layout with -/// a fixed number of tiles in the cross axis. -/// * [SliverGridDelegateWithMaxCrossAxisExtent], which creates a layout with -/// tiles that have a maximum cross-axis extent. -/// * [ScrollNotification] and [NotificationListener], which can be used to watch -/// the scroll position without using a [ScrollController]. -/// * The [catalog of layout widgets](https://flutter.dev/widgets/layout/). -// ignore: camel_case_types -typedef gridView = ExtendedGridView; - -class ExtendedGridView extends BoxScrollView { - /// Creates a scrollable, 2D array of widgets with a custom - /// [SliverGridDelegate]. - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildListDelegate.addRepaintBoundaries] property. Both must not be - /// null. - ExtendedGridView({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required this.gridDelegate, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - List children = const [], - int? semanticChildCount, - super.dragStartBehavior, - super.clipBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.hitTestBehavior, - }) : childrenDelegate = SliverChildListDelegate( - children, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? children.length); - - /// Creates a scrollable, 2D array of widgets that are created on demand. - /// - /// This constructor is appropriate for grid views with a large (or infinite) - /// number of children because the builder is called only for those children - /// that are actually visible. - /// - /// Providing a non-null `itemCount` improves the ability of the [ExtendedGridView] to - /// estimate the maximum scroll extent. - /// - /// `itemBuilder` will be called only with indices greater than or equal to - /// zero and less than `itemCount`. - /// - /// {@macro flutter.widgets.ListView.builder.itemBuilder} - /// - /// {@macro flutter.widgets.PageView.findChildIndexCallback} - /// - /// The [gridDelegate] argument is required. - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildBuilderDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildBuilderDelegate.addRepaintBoundaries] property. The - /// `addSemanticIndexes` argument corresponds to the - /// [SliverChildBuilderDelegate.addSemanticIndexes] property. - ExtendedGridView.builder({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required this.gridDelegate, - required NullableIndexedWidgetBuilder itemBuilder, - ChildIndexGetter? findChildIndexCallback, - int? itemCount, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - int? semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : childrenDelegate = SliverChildBuilderDelegate( - itemBuilder, - findChildIndexCallback: findChildIndexCallback, - childCount: itemCount, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? itemCount); - - /// Creates a scrollable, 2D array of widgets with both a custom - /// [SliverGridDelegate] and a custom [SliverChildDelegate]. - /// - /// To use an [IndexedWidgetBuilder] callback to build children, either use - /// a [SliverChildBuilderDelegate] or use the [GridView.builder] constructor. - const ExtendedGridView.custom({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required this.gridDelegate, - required this.childrenDelegate, - super.cacheExtent, - super.semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }); - - /// Creates a scrollable, 2D array of widgets with a fixed number of tiles in - /// the cross axis. - /// - /// Uses a [SliverGridDelegateWithFixedCrossAxisCount] as the [gridDelegate]. - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildListDelegate.addRepaintBoundaries] property. Both must not be - /// null. - /// - /// See also: - /// - /// * [SliverGrid.count], the equivalent constructor for [SliverGrid]. - ExtendedGridView.count({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required int crossAxisCount, - double mainAxisSpacing = 0.0, - double crossAxisSpacing = 0.0, - double childAspectRatio = 1.0, - double? mainAxisExtent, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - List children = const [], - int? semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : gridDelegate = SliverGridDelegateWithFixedCrossAxisCount( - crossAxisCount: crossAxisCount, - mainAxisSpacing: mainAxisSpacing, - crossAxisSpacing: crossAxisSpacing, - childAspectRatio: childAspectRatio, - mainAxisExtent: mainAxisExtent, - ), - childrenDelegate = SliverChildListDelegate( - children, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? children.length); - - /// Creates a scrollable, 2D array of widgets with tiles that each have a - /// maximum cross-axis extent. - /// - /// Uses a [SliverGridDelegateWithMaxCrossAxisExtent] as the [gridDelegate]. - /// - /// The `addAutomaticKeepAlives` argument corresponds to the - /// [SliverChildListDelegate.addAutomaticKeepAlives] property. The - /// `addRepaintBoundaries` argument corresponds to the - /// [SliverChildListDelegate.addRepaintBoundaries] property. Both must not be - /// null. - /// - /// See also: - /// - /// * [SliverGrid.extent], the equivalent constructor for [SliverGrid]. - ExtendedGridView.extent({ - super.key, - super.scrollDirection, - super.reverse, - super.controller, - super.primary, - super.physics, - super.shrinkWrap, - super.padding, - required double maxCrossAxisExtent, - double mainAxisSpacing = 0.0, - double crossAxisSpacing = 0.0, - double childAspectRatio = 1.0, - double? mainAxisExtent, - bool addAutomaticKeepAlives = true, - bool addRepaintBoundaries = true, - bool addSemanticIndexes = true, - super.cacheExtent, - List children = const [], - int? semanticChildCount, - super.dragStartBehavior, - super.keyboardDismissBehavior, - super.restorationId, - super.clipBehavior, - super.hitTestBehavior, - }) : gridDelegate = SliverGridDelegateWithMaxCrossAxisExtent( - maxCrossAxisExtent: maxCrossAxisExtent, - mainAxisSpacing: mainAxisSpacing, - crossAxisSpacing: crossAxisSpacing, - childAspectRatio: childAspectRatio, - mainAxisExtent: mainAxisExtent, - ), - childrenDelegate = SliverChildListDelegate( - children, - addAutomaticKeepAlives: addAutomaticKeepAlives, - addRepaintBoundaries: addRepaintBoundaries, - addSemanticIndexes: addSemanticIndexes, - ), - super(semanticChildCount: semanticChildCount ?? children.length); - - /// A delegate that controls the layout of the children within the [ExtendedGridView]. - /// - /// The [ExtendedGridView], [GridView.builder], and [GridView.custom] constructors let you specify this - /// delegate explicitly. The other constructors create a [gridDelegate] - /// implicitly. - final SliverGridDelegate gridDelegate; - - /// A delegate that provides the children for the [ExtendedGridView]. - /// - /// The [GridView.custom] constructor lets you specify this delegate - /// explicitly. The other constructors create a [childrenDelegate] that wraps - /// the given child list. - final SliverChildDelegate childrenDelegate; - - @override - Widget buildChildLayout(BuildContext context) { - return SliverGrid(delegate: childrenDelegate, gridDelegate: gridDelegate); - } -} diff --git a/lib/common/widgets/flutter/scroll_view/scrollable.dart b/lib/common/widgets/flutter/scroll_view/scrollable.dart deleted file mode 100644 index fbc3e7818..000000000 --- a/lib/common/widgets/flutter/scroll_view/scrollable.dart +++ /dev/null @@ -1,1870 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -import 'dart:async'; -import 'dart:math' as math; - -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scrollable_helpers.dart'; -import 'package:PiliPlus/common/widgets/gesture/vertical_drag_gesture_recognizer.dart'; -import 'package:PiliPlus/utils/platform_utils.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/gestures.dart'; -import 'package:flutter/rendering.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:flutter/services.dart'; -import 'package:flutter/widgets.dart' - hide Scrollable, ScrollableState, EdgeDraggingAutoScroller; - -export 'package:flutter/physics.dart' show Tolerance; - -// The return type of _performEnsureVisible. -// -// The list of futures represents each pending ScrollPosition call to -// ensureVisible. The returned ScrollableState's context is used to find the -// next potential ancestor Scrollable. -typedef _EnsureVisibleResults = (List>, ScrollableState); - -/// A widget that manages scrolling in one dimension and informs the [Viewport] -/// through which the content is viewed. -/// -/// [Scrollable] implements the interaction model for a scrollable widget, -/// including gesture recognition, but does not have an opinion about how the -/// viewport, which actually displays the children, is constructed. -/// -/// It's rare to construct a [Scrollable] directly. Instead, consider [ListView] -/// or [GridView], which combine scrolling, viewporting, and a layout model. To -/// combine layout models (or to use a custom layout mode), consider using -/// [CustomScrollView]. -/// -/// The static [Scrollable.of] and [Scrollable.ensureVisible] functions are -/// often used to interact with the [Scrollable] widget inside a [ListView] or -/// a [GridView]. -/// -/// To further customize scrolling behavior with a [Scrollable]: -/// -/// 1. You can provide a [viewportBuilder] to customize the child model. For -/// example, [SingleChildScrollView] uses a viewport that displays a single -/// box child whereas [CustomScrollView] uses a [Viewport] or a -/// [ShrinkWrappingViewport], both of which display a list of slivers. -/// -/// 2. You can provide a custom [ScrollController] that creates a custom -/// [ScrollPosition] subclass. For example, [PageView] uses a -/// [PageController], which creates a page-oriented scroll position subclass -/// that keeps the same page visible when the [Scrollable] resizes. -/// -/// ## Persisting the scroll position during a session -/// -/// Scrollables attempt to persist their scroll position using [PageStorage]. -/// This can be disabled by setting [ScrollController.keepScrollOffset] to false -/// on the [controller]. If it is enabled, using a [PageStorageKey] for the -/// [key] of this widget (or one of its ancestors, e.g. a [ScrollView]) is -/// recommended to help disambiguate different [Scrollable]s from each other. -/// -/// See also: -/// -/// * [ListView], which is a commonly used [ScrollView] that displays a -/// scrolling, linear list of child widgets. -/// * [PageView], which is a scrolling list of child widgets that are each the -/// size of the viewport. -/// * [GridView], which is a [ScrollView] that displays a scrolling, 2D array -/// of child widgets. -/// * [CustomScrollView], which is a [ScrollView] that creates custom scroll -/// effects using slivers. -/// * [SingleChildScrollView], which is a scrollable widget that has a single -/// child. -/// * [ScrollNotification] and [NotificationListener], which can be used to watch -/// the scroll position without using a [ScrollController]. -class Scrollable extends StatefulWidget { - /// Creates a widget that scrolls. - const Scrollable({ - super.key, - this.axisDirection = AxisDirection.down, - this.controller, - this.physics, - required this.viewportBuilder, - this.incrementCalculator, - this.excludeFromSemantics = false, - this.semanticChildCount, - this.dragStartBehavior = DragStartBehavior.start, - this.restorationId, - this.scrollBehavior, - this.clipBehavior = Clip.hardEdge, - this.hitTestBehavior = HitTestBehavior.opaque, - }) : assert(semanticChildCount == null || semanticChildCount >= 0); - - /// {@template flutter.widgets.Scrollable.axisDirection} - /// The direction in which this widget scrolls. - /// - /// For example, if the [Scrollable.axisDirection] is [AxisDirection.down], - /// increasing the scroll position will cause content below the bottom of the - /// viewport to become visible through the viewport. Similarly, if the - /// axisDirection is [AxisDirection.right], increasing the scroll position - /// will cause content beyond the right edge of the viewport to become visible - /// through the viewport. - /// - /// Defaults to [AxisDirection.down]. - /// {@endtemplate} - final AxisDirection axisDirection; - - /// {@template flutter.widgets.Scrollable.controller} - /// An object that can be used to control the position to which this widget is - /// scrolled. - /// - /// A [ScrollController] serves several purposes. It can be used to control - /// the initial scroll position (see [ScrollController.initialScrollOffset]). - /// It can be used to control whether the scroll view should automatically - /// save and restore its scroll position in the [PageStorage] (see - /// [ScrollController.keepScrollOffset]). It can be used to read the current - /// scroll position (see [ScrollController.offset]), or change it (see - /// [ScrollController.animateTo]). - /// - /// If null, a [ScrollController] will be created internally by [Scrollable] - /// in order to create and manage the [ScrollPosition]. - /// - /// See also: - /// - /// * [Scrollable.ensureVisible], which animates the scroll position to - /// reveal a given [BuildContext]. - /// {@endtemplate} - final ScrollController? controller; - - /// {@template flutter.widgets.Scrollable.physics} - /// How the widgets should respond to user input. - /// - /// For example, determines how the widget continues to animate after the - /// user stops dragging the scroll view. - /// - /// Defaults to matching platform conventions via the physics provided from - /// the ambient [ScrollConfiguration]. - /// - /// If an explicit [ScrollBehavior] is provided to - /// [Scrollable.scrollBehavior], the [ScrollPhysics] provided by that behavior - /// will take precedence after [Scrollable.physics]. - /// - /// The physics can be changed dynamically, but new physics will only take - /// effect if the _class_ of the provided object changes. Merely constructing - /// a new instance with a different configuration is insufficient to cause the - /// physics to be reapplied. (This is because the final object used is - /// generated dynamically, which can be relatively expensive, and it would be - /// inefficient to speculatively create this object each frame to see if the - /// physics should be updated.) - /// - /// See also: - /// - /// * [AlwaysScrollableScrollPhysics], which can be used to indicate that the - /// scrollable should react to scroll requests (and possible overscroll) - /// even if the scrollable's contents fit without scrolling being necessary. - /// {@endtemplate} - final ScrollPhysics? physics; - - /// Builds the viewport through which the scrollable content is displayed. - /// - /// A typical viewport uses the given [ViewportOffset] to determine which part - /// of its content is actually visible through the viewport. - /// - /// See also: - /// - /// * [Viewport], which is a viewport that displays a list of slivers. - /// * [ShrinkWrappingViewport], which is a viewport that displays a list of - /// slivers and sizes itself based on the size of the slivers. - final ViewportBuilder viewportBuilder; - - /// {@template flutter.widgets.Scrollable.incrementCalculator} - /// An optional function that will be called to calculate the distance to - /// scroll when the scrollable is asked to scroll via the keyboard using a - /// [ScrollAction]. - /// - /// If not supplied, the [Scrollable] will scroll a default amount when a - /// keyboard navigation key is pressed (e.g. pageUp/pageDown, control-upArrow, - /// etc.), or otherwise invoked by a [ScrollAction]. - /// - /// If [incrementCalculator] is null, the default for - /// [ScrollIncrementType.page] is 80% of the size of the scroll window, and - /// for [ScrollIncrementType.line], 50 logical pixels. - /// {@endtemplate} - final ScrollIncrementCalculator? incrementCalculator; - - /// {@template flutter.widgets.scrollable.excludeFromSemantics} - /// Whether the scroll actions introduced by this [Scrollable] are exposed - /// in the semantics tree. - /// - /// Text fields with an overflow are usually scrollable to make sure that the - /// user can get to the beginning/end of the entered text. However, these - /// scrolling actions are generally not exposed to the semantics layer. - /// {@endtemplate} - /// - /// See also: - /// - /// * [GestureDetector.excludeFromSemantics], which is used to accomplish the - /// exclusion. - final bool excludeFromSemantics; - - /// {@template flutter.widgets.scrollable.hitTestBehavior} - /// Defines the behavior of gesture detector used in this [Scrollable]. - /// - /// This defaults to [HitTestBehavior.opaque] which means it prevents targets - /// behind this [Scrollable] from receiving events. - /// {@endtemplate} - /// - /// See also: - /// - /// * [HitTestBehavior], for an explanation on different behaviors. - final HitTestBehavior hitTestBehavior; - - /// The number of children that will contribute semantic information. - /// - /// The value will be null if the number of children is unknown or unbounded. - /// - /// Some subtypes of [ScrollView] can infer this value automatically. For - /// example [ListView] will use the number of widgets in the child list, - /// while the [ListView.separated] constructor will use half that amount. - /// - /// For [CustomScrollView] and other types which do not receive a builder - /// or list of widgets, the child count must be explicitly provided. - /// - /// See also: - /// - /// * [CustomScrollView], for an explanation of scroll semantics. - /// * [SemanticsConfiguration.scrollChildCount], the corresponding semantics property. - final int? semanticChildCount; - - // TODO(jslavitz): Set the DragStartBehavior default to be start across all widgets. - /// {@template flutter.widgets.scrollable.dragStartBehavior} - /// Determines the way that drag start behavior is handled. - /// - /// If set to [DragStartBehavior.start], scrolling drag behavior will - /// begin at the position where the drag gesture won the arena. If set to - /// [DragStartBehavior.down] it will begin at the position where a down - /// event is first detected. - /// - /// In general, setting this to [DragStartBehavior.start] will make drag - /// animation smoother and setting it to [DragStartBehavior.down] will make - /// drag behavior feel slightly more reactive. - /// - /// By default, the drag start behavior is [DragStartBehavior.start]. - /// - /// See also: - /// - /// * [DragGestureRecognizer.dragStartBehavior], which gives an example for - /// the different behaviors. - /// - /// {@endtemplate} - final DragStartBehavior dragStartBehavior; - - /// {@template flutter.widgets.scrollable.restorationId} - /// Restoration ID to save and restore the scroll offset of the scrollable. - /// - /// If a restoration id is provided, the scrollable will persist its current - /// scroll offset and restore it during state restoration. - /// - /// The scroll offset is persisted in a [RestorationBucket] claimed from - /// the surrounding [RestorationScope] using the provided restoration ID. - /// - /// See also: - /// - /// * [RestorationManager], which explains how state restoration works in - /// Flutter. - /// {@endtemplate} - final String? restorationId; - - /// {@template flutter.widgets.scrollable.scrollBehavior} - /// A [ScrollBehavior] that will be applied to this widget individually. - /// - /// Defaults to null, wherein the inherited [ScrollBehavior] is copied and - /// modified to alter the viewport decoration, like [Scrollbar]s. - /// - /// [ScrollBehavior]s also provide [ScrollPhysics]. If an explicit - /// [ScrollPhysics] is provided in [physics], it will take precedence, - /// followed by [scrollBehavior], and then the inherited ancestor - /// [ScrollBehavior]. - /// {@endtemplate} - final ScrollBehavior? scrollBehavior; - - /// {@macro flutter.material.Material.clipBehavior} - /// - /// Defaults to [Clip.hardEdge]. - /// - /// This is passed to decorators in [ScrollableDetails], and does not directly affect - /// clipping of the [Scrollable]. This reflects the same [Clip] that is provided - /// to [ScrollView.clipBehavior] and is supplied to the [Viewport]. - final Clip clipBehavior; - - /// The axis along which the scroll view scrolls. - /// - /// Determined by the [axisDirection]. - Axis get axis => axisDirectionToAxis(axisDirection); - - @override - ScrollableState createState() => ScrollableState(); - - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(EnumProperty('axisDirection', axisDirection)) - ..add(DiagnosticsProperty('physics', physics)) - ..add(StringProperty('restorationId', restorationId)); - } - - /// The state from the closest instance of this class that encloses the given - /// context, or null if none is found. - /// - /// Typical usage is as follows: - /// - /// ```dart - /// ScrollableState? scrollable = Scrollable.maybeOf(context); - /// ``` - /// - /// Calling this method will create a dependency on the [ScrollableState] - /// that is returned, if there is one. This is typically the closest - /// [Scrollable], but may be a more distant ancestor if [axis] is used to - /// target a specific [Scrollable]. - /// - /// Using the optional [Axis] is useful when Scrollables are nested and the - /// target [Scrollable] is not the closest instance. When [axis] is provided, - /// the nearest enclosing [ScrollableState] in that [Axis] is returned, or - /// null if there is none. - /// - /// This finds the nearest _ancestor_ [Scrollable] of the `context`. This - /// means that if the `context` is that of a [Scrollable], it will _not_ find - /// _that_ [Scrollable]. - /// - /// See also: - /// - /// * [Scrollable.of], which is similar to this method, but asserts - /// if no [Scrollable] ancestor is found. - static ScrollableState? maybeOf(BuildContext context, {Axis? axis}) { - // This is the context that will need to establish the dependency. - final originalContext = context; - InheritedElement? element = context - .getElementForInheritedWidgetOfExactType<_ScrollableScope>(); - while (element != null) { - final ScrollableState scrollable = - (element.widget as _ScrollableScope).scrollable; - if (axis == null || - axisDirectionToAxis(scrollable.axisDirection) == axis) { - // Establish the dependency on the correct context. - originalContext.dependOnInheritedElement(element); - return scrollable; - } - context = scrollable.context; - element = context - .getElementForInheritedWidgetOfExactType<_ScrollableScope>(); - } - return null; - } - - /// The state from the closest instance of this class that encloses the given - /// context. - /// - /// Typical usage is as follows: - /// - /// ```dart - /// ScrollableState scrollable = Scrollable.of(context); - /// ``` - /// - /// Calling this method will create a dependency on the [ScrollableState] - /// that is returned, if there is one. This is typically the closest - /// [Scrollable], but may be a more distant ancestor if [axis] is used to - /// target a specific [Scrollable]. - /// - /// Using the optional [Axis] is useful when Scrollables are nested and the - /// target [Scrollable] is not the closest instance. When [axis] is provided, - /// the nearest enclosing [ScrollableState] in that [Axis] is returned. - /// - /// This finds the nearest _ancestor_ [Scrollable] of the `context`. This - /// means that if the `context` is that of a [Scrollable], it will _not_ find - /// _that_ [Scrollable]. - /// - /// If no [Scrollable] ancestor is found, then this method will assert in - /// debug mode, and throw an exception in release mode. - /// - /// See also: - /// - /// * [Scrollable.maybeOf], which is similar to this method, but returns null - /// if no [Scrollable] ancestor is found. - static ScrollableState of(BuildContext context, {Axis? axis}) { - final ScrollableState? scrollableState = maybeOf(context, axis: axis); - assert(() { - if (scrollableState == null) { - throw FlutterError.fromParts([ - ErrorSummary( - 'Scrollable.of() was called with a context that does not contain a ' - 'Scrollable widget.', - ), - ErrorDescription( - 'No Scrollable widget ancestor could be found ' - '${axis == null ? '' : 'for the provided Axis: $axis '}' - 'starting from the context that was passed to Scrollable.of(). This ' - 'can happen because you are using a widget that looks for a Scrollable ' - 'ancestor, but no such ancestor exists.\n' - 'The context used was:\n' - ' $context', - ), - if (axis != null) - ErrorHint( - 'When specifying an axis, this method will only look for a Scrollable ' - 'that matches the given Axis.', - ), - ]); - } - return true; - }()); - return scrollableState!; - } - - /// Provides a heuristic to determine if expensive frame-bound tasks should be - /// deferred for the [context] at a specific point in time. - /// - /// Calling this method does _not_ create a dependency on any other widget. - /// This also means that the value returned is only good for the point in time - /// when it is called, and callers will not get updated if the value changes. - /// - /// The heuristic used is determined by the [physics] of this [Scrollable] - /// via [ScrollPhysics.recommendDeferredLoading]. That method is called with - /// the current [ScrollPosition.activity]'s [ScrollActivity.velocity]. - /// - /// The optional [Axis] allows targeting of a specific [Scrollable] of that - /// axis, useful when Scrollables are nested. When [axis] is provided, - /// [ScrollPosition.recommendDeferredLoading] is called for the nearest - /// [Scrollable] in that [Axis]. - /// - /// If there is no [Scrollable] in the widget tree above the [context], this - /// method returns false. - static bool recommendDeferredLoadingForContext( - BuildContext context, { - Axis? axis, - }) { - _ScrollableScope? widget = context - .getInheritedWidgetOfExactType<_ScrollableScope>(); - while (widget != null) { - if (axis == null || - axisDirectionToAxis(widget.scrollable.axisDirection) == axis) { - return widget.position.recommendDeferredLoading(context); - } - context = widget.scrollable.context; - widget = context.getInheritedWidgetOfExactType<_ScrollableScope>(); - } - return false; - } - - /// Scrolls all scrollables that enclose the given context so as to make the - /// given context visible. - /// - /// If a [Scrollable] enclosing the provided [BuildContext] is a - /// [TwoDimensionalScrollable], both vertical and horizontal axes will ensure - /// the target is made visible. - static Future ensureVisible( - BuildContext context, { - double alignment = 0.0, - Duration duration = Duration.zero, - Curve curve = Curves.ease, - ScrollPositionAlignmentPolicy alignmentPolicy = - ScrollPositionAlignmentPolicy.explicit, - }) { - final futures = >[]; - - // The targetRenderObject is used to record the first target renderObject. - // If there are multiple scrollable widgets nested, the targetRenderObject - // is made to be as visible as possible to improve the user experience. If - // the targetRenderObject is already visible, then let the outer - // renderObject be as visible as possible. - // - // Also see https://github.com/flutter/flutter/issues/65100 - RenderObject? targetRenderObject; - ScrollableState? scrollable = Scrollable.maybeOf(context); - while (scrollable != null) { - final List> newFutures; - (newFutures, scrollable) = scrollable._performEnsureVisible( - context.findRenderObject()!, - alignment: alignment, - duration: duration, - curve: curve, - alignmentPolicy: alignmentPolicy, - targetRenderObject: targetRenderObject, - ); - futures.addAll(newFutures); - - targetRenderObject ??= context.findRenderObject(); - context = scrollable.context; - scrollable = Scrollable.maybeOf(context); - } - - if (futures.isEmpty || duration == Duration.zero) { - return Future.value(); - } - if (futures.length == 1) { - return futures.single; - } - return Future.wait(futures).then((List _) => null); - } -} - -// Enable Scrollable.of() to work as if ScrollableState was an inherited widget. -// ScrollableState.build() always rebuilds its _ScrollableScope. -class _ScrollableScope extends InheritedWidget { - const _ScrollableScope({ - required this.scrollable, - required this.position, - required super.child, - }); - - final ScrollableState scrollable; - final ScrollPosition position; - - @override - bool updateShouldNotify(_ScrollableScope old) { - return position != old.position; - } -} - -/// State object for a [Scrollable] widget. -/// -/// To manipulate a [Scrollable] widget's scroll position, use the object -/// obtained from the [position] property. -/// -/// To be informed of when a [Scrollable] widget is scrolling, use a -/// [NotificationListener] to listen for [ScrollNotification] notifications. -/// -/// This class is not intended to be subclassed. To specialize the behavior of a -/// [Scrollable], provide it with a [ScrollPhysics]. -class ScrollableState extends State - with TickerProviderStateMixin, RestorationMixin - implements ScrollContext { - // GETTERS - - /// The manager for this [Scrollable] widget's viewport position. - /// - /// To control what kind of [ScrollPosition] is created for a [Scrollable], - /// provide it with custom [ScrollController] that creates the appropriate - /// [ScrollPosition] in its [ScrollController.createScrollPosition] method. - ScrollPosition get position => _position!; - ScrollPosition? _position; - - /// The resolved [ScrollPhysics] of the [ScrollableState]. - ScrollPhysics? get resolvedPhysics => _physics; - ScrollPhysics? _physics; - - /// An [Offset] that represents the absolute distance from the origin, or 0, - /// of the [ScrollPosition] expressed in the associated [Axis]. - /// - /// Used by [EdgeDraggingAutoScroller] to progress the position forward when a - /// drag gesture reaches the edge of the [Viewport]. - Offset get deltaToScrollOrigin => switch (axisDirection) { - AxisDirection.up => Offset(0, -position.pixels), - AxisDirection.down => Offset(0, position.pixels), - AxisDirection.left => Offset(-position.pixels, 0), - AxisDirection.right => Offset(position.pixels, 0), - }; - - ScrollController get _effectiveScrollController => - widget.controller ?? _fallbackScrollController!; - - @override - AxisDirection get axisDirection => widget.axisDirection; - - @override - TickerProvider get vsync => this; - - @override - double get devicePixelRatio => _devicePixelRatio; - late double _devicePixelRatio; - - @override - BuildContext? get notificationContext => _gestureDetectorKey.currentContext; - - @override - BuildContext get storageContext => context; - - @override - String? get restorationId => widget.restorationId; - final _RestorableScrollOffset _persistedScrollOffset = - _RestorableScrollOffset(); - - late ScrollBehavior _configuration; - ScrollController? _fallbackScrollController; - DeviceGestureSettings? _mediaQueryGestureSettings; - - // Only call this from places that will definitely trigger a rebuild. - void _updatePosition() { - _configuration = widget.scrollBehavior ?? ScrollConfiguration.of(context); - final ScrollPhysics? physicsFromWidget = - widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context); - _physics = _configuration.getScrollPhysics(context); - _physics = physicsFromWidget?.applyTo(_physics) ?? _physics; - - final ScrollPosition? oldPosition = _position; - if (oldPosition != null) { - _effectiveScrollController.detach(oldPosition); - // It's important that we not dispose the old position until after the - // viewport has had a chance to unregister its listeners from the old - // position. So, schedule a microtask to do it. - scheduleMicrotask(oldPosition.dispose); - } - - _position = _effectiveScrollController.createScrollPosition( - _physics!, - this, - oldPosition, - ); - assert(_position != null); - _effectiveScrollController.attach(position); - } - - @protected - @override - void restoreState(RestorationBucket? oldBucket, bool initialRestore) { - registerForRestoration(_persistedScrollOffset, 'offset'); - assert(_position != null); - if (_persistedScrollOffset.value != null) { - position.restoreOffset( - _persistedScrollOffset.value!, - initialRestore: initialRestore, - ); - } - } - - @protected - @override - void saveOffset(double offset) { - assert(debugIsSerializableForRestoration(offset)); - _persistedScrollOffset.value = offset; - // [saveOffset] is called after a scrolling ends and it is usually not - // followed by a frame. Therefore, manually flush restoration data. - ServicesBinding.instance.restorationManager.flushData(); - } - - @protected - @override - void initState() { - if (widget.controller == null) { - _fallbackScrollController = ScrollController(); - } - super.initState(); - } - - @protected - @override - void didChangeDependencies() { - _mediaQueryGestureSettings = MediaQuery.maybeGestureSettingsOf(context); - _devicePixelRatio = - MediaQuery.maybeDevicePixelRatioOf(context) ?? - View.of(context).devicePixelRatio; - _updatePosition(); - super.didChangeDependencies(); - } - - bool _shouldUpdatePosition(Scrollable oldWidget) { - if ((widget.scrollBehavior == null) != (oldWidget.scrollBehavior == null)) { - return true; - } - if (widget.scrollBehavior != null && - oldWidget.scrollBehavior != null && - widget.scrollBehavior!.shouldNotify(oldWidget.scrollBehavior!)) { - return true; - } - ScrollPhysics? newPhysics = - widget.physics ?? widget.scrollBehavior?.getScrollPhysics(context); - ScrollPhysics? oldPhysics = - oldWidget.physics ?? - oldWidget.scrollBehavior?.getScrollPhysics(context); - do { - if (newPhysics?.runtimeType != oldPhysics?.runtimeType) { - return true; - } - newPhysics = newPhysics?.parent; - oldPhysics = oldPhysics?.parent; - } while (newPhysics != null || oldPhysics != null); - - return widget.controller?.runtimeType != oldWidget.controller?.runtimeType; - } - - @protected - @override - void didUpdateWidget(Scrollable oldWidget) { - super.didUpdateWidget(oldWidget); - - if (widget.controller != oldWidget.controller) { - if (oldWidget.controller == null) { - // The old controller was null, meaning the fallback cannot be null. - // Dispose of the fallback. - assert(_fallbackScrollController != null); - assert(widget.controller != null); - _fallbackScrollController!.detach(position); - _fallbackScrollController!.dispose(); - _fallbackScrollController = null; - } else { - // The old controller was not null, detach. - oldWidget.controller?.detach(position); - if (widget.controller == null) { - // If the new controller is null, we need to set up the fallback - // ScrollController. - _fallbackScrollController = ScrollController(); - } - } - // Attach the updated effective scroll controller. - _effectiveScrollController.attach(position); - } - - if (_shouldUpdatePosition(oldWidget)) { - _updatePosition(); - } - } - - @protected - @override - void dispose() { - if (widget.controller != null) { - widget.controller!.detach(position); - } else { - _fallbackScrollController?.detach(position); - _fallbackScrollController?.dispose(); - } - - position.dispose(); - _persistedScrollOffset.dispose(); - super.dispose(); - } - - // SEMANTICS - - final GlobalKey _scrollSemanticsKey = GlobalKey(); - - @override - @protected - void setSemanticsActions(Set actions) { - if (_gestureDetectorKey.currentState != null) { - _gestureDetectorKey.currentState!.replaceSemanticsActions(actions); - } - } - - // GESTURE RECOGNITION AND POINTER IGNORING - - final GlobalKey _gestureDetectorKey = - GlobalKey(); - final GlobalKey _ignorePointerKey = GlobalKey(); - - // This field is set during layout, and then reused until the next time it is set. - Map _gestureRecognizers = - const {}; - bool _shouldIgnorePointer = false; - - bool? _lastCanDrag; - Axis? _lastAxisDirection; - - @override - @protected - void setCanDrag(bool value) { - if (value == _lastCanDrag && - (!value || widget.axis == _lastAxisDirection)) { - return; - } - if (!value) { - _gestureRecognizers = const {}; - // Cancel the active hold/drag (if any) because the gesture recognizers - // will soon be disposed by our RawGestureDetector, and we won't be - // receiving pointer up events to cancel the hold/drag. - _handleDragCancel(); - } else { - switch (widget.axis) { - case Axis.vertical: - _gestureRecognizers = { - CustomVerticalDragGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - CustomVerticalDragGestureRecognizer - >( - () => CustomVerticalDragGestureRecognizer( - supportedDevices: _configuration.dragDevices, - ), - (CustomVerticalDragGestureRecognizer instance) { - instance - ..isDyAllowed = PlatformUtils.isMobile - ? isDyAllowed - : null - ..onDown = _handleDragDown - ..onStart = _handleDragStart - ..onUpdate = _handleDragUpdate - ..onEnd = _handleDragEnd - ..onCancel = _handleDragCancel - ..minFlingDistance = _physics?.minFlingDistance - ..minFlingVelocity = _physics?.minFlingVelocity - ..maxFlingVelocity = _physics?.maxFlingVelocity - ..velocityTrackerBuilder = _configuration - .velocityTrackerBuilder(context) - ..dragStartBehavior = widget.dragStartBehavior - ..multitouchDragStrategy = _configuration - .getMultitouchDragStrategy(context) - ..gestureSettings = _mediaQueryGestureSettings - ..supportedDevices = _configuration.dragDevices; - }, - ), - }; - case Axis.horizontal: - _gestureRecognizers = { - HorizontalDragGestureRecognizer: - GestureRecognizerFactoryWithHandlers< - HorizontalDragGestureRecognizer - >( - () => HorizontalDragGestureRecognizer( - supportedDevices: _configuration.dragDevices, - ), - (HorizontalDragGestureRecognizer instance) { - instance - ..onDown = _handleDragDown - ..onStart = _handleDragStart - ..onUpdate = _handleDragUpdate - ..onEnd = _handleDragEnd - ..onCancel = _handleDragCancel - ..minFlingDistance = _physics?.minFlingDistance - ..minFlingVelocity = _physics?.minFlingVelocity - ..maxFlingVelocity = _physics?.maxFlingVelocity - ..velocityTrackerBuilder = _configuration - .velocityTrackerBuilder(context) - ..dragStartBehavior = widget.dragStartBehavior - ..multitouchDragStrategy = _configuration - .getMultitouchDragStrategy(context) - ..gestureSettings = _mediaQueryGestureSettings - ..supportedDevices = _configuration.dragDevices; - }, - ), - }; - } - } - _lastCanDrag = value; - _lastAxisDirection = widget.axis; - if (_gestureDetectorKey.currentState != null) { - _gestureDetectorKey.currentState!.replaceGestureRecognizers( - _gestureRecognizers, - ); - } - } - - @override - @protected - void setIgnorePointer(bool value) { - if (_shouldIgnorePointer == value) { - return; - } - _shouldIgnorePointer = value; - if (_ignorePointerKey.currentContext != null) { - final renderBox = - _ignorePointerKey.currentContext!.findRenderObject()! - as RenderIgnorePointer; - renderBox.ignoring = _shouldIgnorePointer; - } - } - - // TOUCH HANDLERS - - Drag? _drag; - ScrollHoldController? _hold; - - bool isDyAllowed(double dy) { - return position.viewportDimension - dy > 30; - } - - void _handleDragDown(DragDownDetails details) { - assert(_drag == null); - assert(_hold == null); - _hold = position.hold(_disposeHold); - } - - void _handleDragStart(DragStartDetails details) { - // It's possible for _hold to become null between _handleDragDown and - // _handleDragStart, for example if some user code calls jumpTo or otherwise - // triggers a new activity to begin. - assert(_drag == null); - _drag = position.drag(details, _disposeDrag); - assert(_drag != null); - // _hold might be non-null if the scroll position is currently animating. - if (_hold != null) { - _disposeHold(); - } - } - - void _handleDragUpdate(DragUpdateDetails details) { - // _drag might be null if the drag activity ended and called _disposeDrag. - assert(_hold == null || _drag == null); - _drag?.update(details); - } - - void _handleDragEnd(DragEndDetails details) { - // _drag might be null if the drag activity ended and called _disposeDrag. - assert(_hold == null || _drag == null); - _drag?.end(details); - assert(_drag == null); - } - - void _handleDragCancel() { - if (_gestureDetectorKey.currentContext == null) { - // The cancel was caused by the GestureDetector getting disposed, which - // means we will get disposed momentarily as well and shouldn't do - // any work. - return; - } - // _hold might be null if the drag started. - // _drag might be null if the drag activity ended and called _disposeDrag. - assert(_hold == null || _drag == null); - _hold?.cancel(); - _drag?.cancel(); - assert(_hold == null); - assert(_drag == null); - } - - void _disposeHold() { - _hold = null; - } - - void _disposeDrag() { - _drag = null; - } - - // SCROLL WHEEL - - // Returns the offset that should result from applying [event] to the current - // position, taking min/max scroll extent into account. - double _targetScrollOffsetForPointerScroll(double delta) { - return math.min( - math.max(position.pixels + delta, position.minScrollExtent), - position.maxScrollExtent, - ); - } - - // Returns the delta that should result from applying [event] with axis, - // direction, and any modifiers specified by the ScrollBehavior taken into - // account. - double _pointerSignalEventDelta(PointerScrollEvent event) { - final Set pressed = - HardwareKeyboard.instance.logicalKeysPressed; - final bool flipAxes = - pressed.any(_configuration.pointerAxisModifiers.contains) && - // Axes are only flipped for physical mouse wheel input. - // On some platforms, like web, trackpad input is handled through pointer - // signals, but should not be included in this axis modifying behavior. - // This is because on a trackpad, all directional axes are available to - // the user, while mouse scroll wheels typically are restricted to one - // axis. - event.kind == PointerDeviceKind.mouse; - - final Axis axis = flipAxes ? flipAxis(widget.axis) : widget.axis; - final double delta = switch (axis) { - Axis.horizontal => event.scrollDelta.dx, - Axis.vertical => event.scrollDelta.dy, - }; - - return axisDirectionIsReversed(widget.axisDirection) ? -delta : delta; - } - - void _receivedPointerSignal(PointerSignalEvent event) { - if (event is PointerScrollEvent && _position != null) { - if (_physics != null && !_physics!.shouldAcceptUserOffset(position)) { - // The handler won't use the `event`, so allow the platform to trigger - // any default native actions. - event.respond(allowPlatformDefault: true); - return; - } - final double delta = _pointerSignalEventDelta(event); - final double targetScrollOffset = _targetScrollOffsetForPointerScroll( - delta, - ); - // Only express interest in the event if it would actually result in a scroll. - if (delta != 0.0 && targetScrollOffset != position.pixels) { - GestureBinding.instance.pointerSignalResolver.register( - event, - _handlePointerScroll, - ); - return; - } - // The `event` won't result in a scroll, so allow the platform to trigger - // any default native actions. - event.respond(allowPlatformDefault: true); - } else if (event is PointerScrollInertiaCancelEvent) { - position.pointerScroll(0); - // Don't use the pointer signal resolver, all hit-tested scrollables should stop. - } - } - - void _handlePointerScroll(PointerEvent event) { - assert(event is PointerScrollEvent); - final double delta = _pointerSignalEventDelta(event as PointerScrollEvent); - final double targetScrollOffset = _targetScrollOffsetForPointerScroll( - delta, - ); - if (delta != 0.0 && targetScrollOffset != position.pixels) { - position.pointerScroll(delta); - } - } - - bool _handleScrollMetricsNotification( - ScrollMetricsNotification notification, - ) { - if (notification.depth == 0) { - final RenderObject? scrollSemanticsRenderObject = _scrollSemanticsKey - .currentContext - ?.findRenderObject(); - if (scrollSemanticsRenderObject != null) { - scrollSemanticsRenderObject.markNeedsSemanticsUpdate(); - } - } - return false; - } - - Widget _buildChrome(BuildContext context, Widget child) { - final details = ScrollableDetails( - direction: widget.axisDirection, - controller: _effectiveScrollController, - decorationClipBehavior: widget.clipBehavior, - ); - - return _configuration.buildScrollbar( - context, - _configuration.buildOverscrollIndicator(context, child, details), - details, - ); - } - - // DESCRIPTION - - @protected - @override - Widget build(BuildContext context) { - assert(_position != null); - // _ScrollableScope must be placed above the BuildContext returned by notificationContext - // so that we can get this ScrollableState by doing the following: - // - // ScrollNotification notification; - // Scrollable.of(notification.context) - // - // Since notificationContext is pointing to _gestureDetectorKey.context, _ScrollableScope - // must be placed above the widget using it: RawGestureDetector - Widget result = _ScrollableScope( - scrollable: this, - position: position, - child: Listener( - onPointerSignal: _receivedPointerSignal, - child: RawGestureDetector( - key: _gestureDetectorKey, - gestures: _gestureRecognizers, - behavior: widget.hitTestBehavior, - excludeFromSemantics: widget.excludeFromSemantics, - child: Semantics( - explicitChildNodes: !widget.excludeFromSemantics, - child: IgnorePointer( - key: _ignorePointerKey, - ignoring: _shouldIgnorePointer, - child: widget.viewportBuilder(context, position), - ), - ), - ), - ), - ); - - if (!widget.excludeFromSemantics) { - result = NotificationListener( - onNotification: _handleScrollMetricsNotification, - child: _ScrollSemantics( - key: _scrollSemanticsKey, - position: position, - allowImplicitScrolling: _physics!.allowImplicitScrolling, - axis: widget.axis, - semanticChildCount: widget.semanticChildCount, - child: result, - ), - ); - } - - result = _buildChrome(context, result); - - // Selection is only enabled when there is a parent registrar. - final SelectionRegistrar? registrar = SelectionContainer.maybeOf(context); - if (registrar != null) { - result = _ScrollableSelectionHandler( - state: this, - position: position, - registrar: registrar, - child: result, - ); - } - - return result; - } - - // Returns the Future from calling ensureVisible for the ScrollPosition, as - // as well as this ScrollableState instance so its context can be used to - // check for other ancestor Scrollables in executing ensureVisible. - _EnsureVisibleResults _performEnsureVisible( - RenderObject object, { - double alignment = 0.0, - Duration duration = Duration.zero, - Curve curve = Curves.ease, - ScrollPositionAlignmentPolicy alignmentPolicy = - ScrollPositionAlignmentPolicy.explicit, - RenderObject? targetRenderObject, - }) { - final Future ensureVisibleFuture = position.ensureVisible( - object, - alignment: alignment, - duration: duration, - curve: curve, - alignmentPolicy: alignmentPolicy, - targetRenderObject: targetRenderObject, - ); - return (>[ensureVisibleFuture], this); - } - - @protected - @override - void debugFillProperties(DiagnosticPropertiesBuilder properties) { - super.debugFillProperties(properties); - properties - ..add(DiagnosticsProperty('position', _position)) - ..add( - DiagnosticsProperty('effective physics', _physics), - ); - } -} - -/// A widget to handle selection for a scrollable. -/// -/// This widget registers itself to the [registrar] and uses -/// [SelectionContainer] to collect selectables from its subtree. -class _ScrollableSelectionHandler extends StatefulWidget { - const _ScrollableSelectionHandler({ - required this.state, - required this.position, - required this.registrar, - required this.child, - }); - - final ScrollableState state; - final ScrollPosition position; - final Widget child; - final SelectionRegistrar registrar; - - @override - _ScrollableSelectionHandlerState createState() => - _ScrollableSelectionHandlerState(); -} - -class _ScrollableSelectionHandlerState - extends State<_ScrollableSelectionHandler> { - late _ScrollableSelectionContainerDelegate _selectionDelegate; - - @override - void initState() { - super.initState(); - _selectionDelegate = _ScrollableSelectionContainerDelegate( - state: widget.state, - position: widget.position, - ); - } - - @override - void didUpdateWidget(_ScrollableSelectionHandler oldWidget) { - super.didUpdateWidget(oldWidget); - if (oldWidget.position != widget.position) { - _selectionDelegate.position = widget.position; - } - } - - @override - void dispose() { - _selectionDelegate.dispose(); - super.dispose(); - } - - @override - Widget build(BuildContext context) { - return SelectionContainer( - registrar: widget.registrar, - delegate: _selectionDelegate, - child: widget.child, - ); - } -} - -/// This updater handles the case where the selectables change frequently, and -/// it optimizes toward scrolling updates. -/// -/// It keeps track of the drag start offset relative to scroll origin for every -/// selectable. The records are used to determine whether the selection is up to -/// date with the scroll position when it sends the drag update event to a -/// selectable. -class _ScrollableSelectionContainerDelegate - extends MultiSelectableSelectionContainerDelegate { - _ScrollableSelectionContainerDelegate({ - required this.state, - required ScrollPosition position, - }) : _position = position, - _autoScroller = EdgeDraggingAutoScroller( - state, - velocityScalar: _kDefaultSelectToScrollVelocityScalar, - ) { - _position.addListener(_scheduleLayoutChange); - } - - // Pointer drag is a single point, it should not have a size. - static const double _kDefaultDragTargetSize = 0; - - // An eye-balled value for a smooth scrolling speed. - static const double _kDefaultSelectToScrollVelocityScalar = 30; - - final ScrollableState state; - final EdgeDraggingAutoScroller _autoScroller; - bool _scheduledLayoutChange = false; - Offset? _currentDragStartRelatedToOrigin; - Offset? _currentDragEndRelatedToOrigin; - - // The scrollable only auto scrolls if the selection starts in the scrollable. - bool _selectionStartsInScrollable = false; - - ScrollPosition get position => _position; - ScrollPosition _position; - set position(ScrollPosition other) { - if (other == _position) { - return; - } - _position.removeListener(_scheduleLayoutChange); - _position = other; - _position.addListener(_scheduleLayoutChange); - } - - // The layout will only be updated a frame later than position changes. - // Schedule PostFrameCallback to capture the accurate layout. - void _scheduleLayoutChange() { - if (_scheduledLayoutChange) { - return; - } - _scheduledLayoutChange = true; - SchedulerBinding.instance.addPostFrameCallback((Duration timeStamp) { - if (!_scheduledLayoutChange) { - return; - } - _scheduledLayoutChange = false; - layoutDidChange(); - }, debugLabel: 'ScrollableSelectionContainer.layoutDidChange'); - } - - /// Stores the scroll offset when a scrollable receives the last - /// [SelectionEdgeUpdateEvent]. - /// - /// The stored scroll offset may be null if a scrollable never receives a - /// [SelectionEdgeUpdateEvent]. - /// - /// When a new [SelectionEdgeUpdateEvent] is dispatched to a selectable, this - /// updater checks the current scroll offset against the one stored in these - /// records. If the scroll offset is different, it synthesizes an opposite - /// [SelectionEdgeUpdateEvent] and dispatches the event before dispatching the - /// new event. - /// - /// For example, if a selectable receives an end [SelectionEdgeUpdateEvent] - /// and its scroll offset in the records is different from the current value, - /// it synthesizes a start [SelectionEdgeUpdateEvent] and dispatches it before - /// dispatching the original end [SelectionEdgeUpdateEvent]. - final Map _selectableStartEdgeUpdateRecords = - {}; - final Map _selectableEndEdgeUpdateRecords = - {}; - - @override - void didChangeSelectables() { - final Set selectableSet = selectables.toSet(); - _selectableStartEdgeUpdateRecords.removeWhere( - (Selectable key, double value) => !selectableSet.contains(key), - ); - _selectableEndEdgeUpdateRecords.removeWhere( - (Selectable key, double value) => !selectableSet.contains(key), - ); - super.didChangeSelectables(); - } - - @override - SelectionResult handleClearSelection(ClearSelectionEvent event) { - _selectableStartEdgeUpdateRecords.clear(); - _selectableEndEdgeUpdateRecords.clear(); - _currentDragStartRelatedToOrigin = null; - _currentDragEndRelatedToOrigin = null; - _selectionStartsInScrollable = false; - return super.handleClearSelection(event); - } - - @override - SelectionResult handleSelectionEdgeUpdate(SelectionEdgeUpdateEvent event) { - if (_currentDragEndRelatedToOrigin == null && - _currentDragStartRelatedToOrigin == null) { - assert(!_selectionStartsInScrollable); - _selectionStartsInScrollable = _globalPositionInScrollable( - event.globalPosition, - ); - } - final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); - if (event.type == SelectionEventType.endEdgeUpdate) { - _currentDragEndRelatedToOrigin = _inferPositionRelatedToOrigin( - event.globalPosition, - ); - final Offset endOffset = _currentDragEndRelatedToOrigin!.translate( - -deltaToOrigin.dx, - -deltaToOrigin.dy, - ); - event = SelectionEdgeUpdateEvent.forEnd( - globalPosition: endOffset, - granularity: event.granularity, - ); - } else { - _currentDragStartRelatedToOrigin = _inferPositionRelatedToOrigin( - event.globalPosition, - ); - final Offset startOffset = _currentDragStartRelatedToOrigin!.translate( - -deltaToOrigin.dx, - -deltaToOrigin.dy, - ); - event = SelectionEdgeUpdateEvent.forStart( - globalPosition: startOffset, - granularity: event.granularity, - ); - } - final SelectionResult result = super.handleSelectionEdgeUpdate(event); - - // Result may be pending if one of the selectable child is also a scrollable. - // In that case, the parent scrollable needs to wait for the child to finish - // scrolling. - if (result == SelectionResult.pending) { - _autoScroller.stopAutoScroll(); - return result; - } - if (_selectionStartsInScrollable) { - _autoScroller.startAutoScrollIfNecessary(_dragTargetFromEvent(event)); - if (_autoScroller.scrolling) { - return SelectionResult.pending; - } - } - return result; - } - - Offset _inferPositionRelatedToOrigin(Offset globalPosition) { - final box = state.context.findRenderObject()! as RenderBox; - final Offset localPosition = box.globalToLocal(globalPosition); - if (!_selectionStartsInScrollable) { - // If the selection starts outside of the scrollable, selecting across the - // scrollable boundary will act as selecting the entire content in the - // scrollable. This logic move the offset to the 0.0 or infinity to cover - // the entire content if the input position is outside of the scrollable. - if (localPosition.dy < 0 || localPosition.dx < 0) { - return box.localToGlobal(Offset.zero); - } - if (localPosition.dy > box.size.height || - localPosition.dx > box.size.width) { - return Offset.infinite; - } - } - final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); - return box.localToGlobal( - localPosition.translate(deltaToOrigin.dx, deltaToOrigin.dy), - ); - } - - /// Infers the [_currentDragStartRelatedToOrigin] and - /// [_currentDragEndRelatedToOrigin] from the geometry. - /// - /// This method is called after a select word and select all event where the - /// selection is triggered by none drag events. The - /// [_currentDragStartRelatedToOrigin] and [_currentDragEndRelatedToOrigin] - /// are essential to handle future [SelectionEdgeUpdateEvent]s. - void _updateDragLocationsFromGeometries({ - bool forceUpdateStart = true, - bool forceUpdateEnd = true, - }) { - final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); - final box = state.context.findRenderObject()! as RenderBox; - final Matrix4 transform = box.getTransformTo(null); - if (currentSelectionStartIndex != -1 && - (_currentDragStartRelatedToOrigin == null || forceUpdateStart)) { - final SelectionGeometry geometry = - selectables[currentSelectionStartIndex].value; - assert(geometry.hasSelection); - final SelectionPoint start = geometry.startSelectionPoint!; - final Matrix4 childTransform = selectables[currentSelectionStartIndex] - .getTransformTo(box); - final Offset localDragStart = MatrixUtils.transformPoint( - childTransform, - start.localPosition + Offset(0, -start.lineHeight / 2), - ); - _currentDragStartRelatedToOrigin = MatrixUtils.transformPoint( - transform, - localDragStart + deltaToOrigin, - ); - } - if (currentSelectionEndIndex != -1 && - (_currentDragEndRelatedToOrigin == null || forceUpdateEnd)) { - final SelectionGeometry geometry = - selectables[currentSelectionEndIndex].value; - assert(geometry.hasSelection); - final SelectionPoint end = geometry.endSelectionPoint!; - final Matrix4 childTransform = selectables[currentSelectionEndIndex] - .getTransformTo(box); - final Offset localDragEnd = MatrixUtils.transformPoint( - childTransform, - end.localPosition + Offset(0, -end.lineHeight / 2), - ); - _currentDragEndRelatedToOrigin = MatrixUtils.transformPoint( - transform, - localDragEnd + deltaToOrigin, - ); - } - } - - @override - SelectionResult handleSelectAll(SelectAllSelectionEvent event) { - assert(!_selectionStartsInScrollable); - final SelectionResult result = super.handleSelectAll(event); - assert( - (currentSelectionStartIndex == -1) == (currentSelectionEndIndex == -1), - ); - if (currentSelectionStartIndex != -1) { - _updateDragLocationsFromGeometries(); - } - return result; - } - - @override - SelectionResult handleSelectWord(SelectWordSelectionEvent event) { - _selectionStartsInScrollable = _globalPositionInScrollable( - event.globalPosition, - ); - final SelectionResult result = super.handleSelectWord(event); - _updateDragLocationsFromGeometries(); - return result; - } - - @override - SelectionResult handleGranularlyExtendSelection( - GranularlyExtendSelectionEvent event, - ) { - final SelectionResult result = super.handleGranularlyExtendSelection(event); - // The selection geometry may not have the accurate offset for the edges - // that are outside of the viewport whose transform may not be valid. Only - // the edge this event is updating is sure to be accurate. - _updateDragLocationsFromGeometries( - forceUpdateStart: !event.isEnd, - forceUpdateEnd: event.isEnd, - ); - if (_selectionStartsInScrollable) { - _jumpToEdge(event.isEnd); - } - return result; - } - - @override - SelectionResult handleDirectionallyExtendSelection( - DirectionallyExtendSelectionEvent event, - ) { - final SelectionResult result = super.handleDirectionallyExtendSelection( - event, - ); - // The selection geometry may not have the accurate offset for the edges - // that are outside of the viewport whose transform may not be valid. Only - // the edge this event is updating is sure to be accurate. - _updateDragLocationsFromGeometries( - forceUpdateStart: !event.isEnd, - forceUpdateEnd: event.isEnd, - ); - if (_selectionStartsInScrollable) { - _jumpToEdge(event.isEnd); - } - return result; - } - - void _jumpToEdge(bool isExtent) { - final Selectable selectable; - final double? lineHeight; - final SelectionPoint? edge; - if (isExtent) { - selectable = selectables[currentSelectionEndIndex]; - edge = selectable.value.endSelectionPoint; - lineHeight = selectable.value.endSelectionPoint!.lineHeight; - } else { - selectable = selectables[currentSelectionStartIndex]; - edge = selectable.value.startSelectionPoint; - lineHeight = selectable.value.startSelectionPoint?.lineHeight; - } - if (lineHeight == null || edge == null) { - return; - } - final scrollableBox = state.context.findRenderObject()! as RenderBox; - final Matrix4 transform = selectable.getTransformTo(scrollableBox); - final Offset edgeOffsetInScrollableCoordinates = MatrixUtils.transformPoint( - transform, - edge.localPosition, - ); - final scrollableRect = Rect.fromLTRB( - 0, - 0, - scrollableBox.size.width, - scrollableBox.size.height, - ); - switch (state.axisDirection) { - case AxisDirection.up: - final double edgeBottom = edgeOffsetInScrollableCoordinates.dy; - final double edgeTop = - edgeOffsetInScrollableCoordinates.dy - lineHeight; - if (edgeBottom >= scrollableRect.bottom && - edgeTop <= scrollableRect.top) { - return; - } - if (edgeBottom > scrollableRect.bottom) { - position.jumpTo(position.pixels + scrollableRect.bottom - edgeBottom); - return; - } - if (edgeTop < scrollableRect.top) { - position.jumpTo(position.pixels + scrollableRect.top - edgeTop); - } - return; - case AxisDirection.right: - final double edge = edgeOffsetInScrollableCoordinates.dx; - if (edge >= scrollableRect.right && edge <= scrollableRect.left) { - return; - } - if (edge > scrollableRect.right) { - position.jumpTo(position.pixels + edge - scrollableRect.right); - return; - } - if (edge < scrollableRect.left) { - position.jumpTo(position.pixels + edge - scrollableRect.left); - } - return; - case AxisDirection.down: - final double edgeBottom = edgeOffsetInScrollableCoordinates.dy; - final double edgeTop = - edgeOffsetInScrollableCoordinates.dy - lineHeight; - if (edgeBottom >= scrollableRect.bottom && - edgeTop <= scrollableRect.top) { - return; - } - if (edgeBottom > scrollableRect.bottom) { - position.jumpTo(position.pixels + edgeBottom - scrollableRect.bottom); - return; - } - if (edgeTop < scrollableRect.top) { - position.jumpTo(position.pixels + edgeTop - scrollableRect.top); - } - return; - case AxisDirection.left: - final double edge = edgeOffsetInScrollableCoordinates.dx; - if (edge >= scrollableRect.right && edge <= scrollableRect.left) { - return; - } - if (edge > scrollableRect.right) { - position.jumpTo(position.pixels + scrollableRect.right - edge); - return; - } - if (edge < scrollableRect.left) { - position.jumpTo(position.pixels + scrollableRect.left - edge); - } - return; - } - } - - bool _globalPositionInScrollable(Offset globalPosition) { - final box = state.context.findRenderObject()! as RenderBox; - final Offset localPosition = box.globalToLocal(globalPosition); - final rect = Rect.fromLTWH(0, 0, box.size.width, box.size.height); - return rect.contains(localPosition); - } - - Rect _dragTargetFromEvent(SelectionEdgeUpdateEvent event) { - return Rect.fromCenter( - center: event.globalPosition, - width: _kDefaultDragTargetSize, - height: _kDefaultDragTargetSize, - ); - } - - @override - SelectionResult dispatchSelectionEventToChild( - Selectable selectable, - SelectionEvent event, - ) { - switch (event.type) { - case SelectionEventType.startEdgeUpdate: - _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; - ensureChildUpdated(selectable); - case SelectionEventType.endEdgeUpdate: - _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; - ensureChildUpdated(selectable); - case SelectionEventType.granularlyExtendSelection: - case SelectionEventType.directionallyExtendSelection: - ensureChildUpdated(selectable); - _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; - _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; - case SelectionEventType.clear: - _selectableEndEdgeUpdateRecords.remove(selectable); - _selectableStartEdgeUpdateRecords.remove(selectable); - case SelectionEventType.selectAll: - case SelectionEventType.selectWord: - case SelectionEventType.selectParagraph: - _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; - _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; - } - return super.dispatchSelectionEventToChild(selectable, event); - } - - @override - void ensureChildUpdated(Selectable selectable) { - final double newRecord = state.position.pixels; - final double? previousStartRecord = - _selectableStartEdgeUpdateRecords[selectable]; - if (_currentDragStartRelatedToOrigin != null && - (previousStartRecord == null || - (newRecord - previousStartRecord).abs() > - precisionErrorTolerance)) { - // Make sure the selectable has up to date events. - final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); - final Offset startOffset = _currentDragStartRelatedToOrigin!.translate( - -deltaToOrigin.dx, - -deltaToOrigin.dy, - ); - selectable.dispatchSelectionEvent( - SelectionEdgeUpdateEvent.forStart(globalPosition: startOffset), - ); - // Make sure we track that we have synthesized a start event for this selectable, - // so we don't synthesize events unnecessarily. - _selectableStartEdgeUpdateRecords[selectable] = state.position.pixels; - } - final double? previousEndRecord = - _selectableEndEdgeUpdateRecords[selectable]; - if (_currentDragEndRelatedToOrigin != null && - (previousEndRecord == null || - (newRecord - previousEndRecord).abs() > precisionErrorTolerance)) { - // Make sure the selectable has up to date events. - final Offset deltaToOrigin = _getDeltaToScrollOrigin(state); - final Offset endOffset = _currentDragEndRelatedToOrigin!.translate( - -deltaToOrigin.dx, - -deltaToOrigin.dy, - ); - selectable.dispatchSelectionEvent( - SelectionEdgeUpdateEvent.forEnd(globalPosition: endOffset), - ); - // Make sure we track that we have synthesized an end event for this selectable, - // so we don't synthesize events unnecessarily. - _selectableEndEdgeUpdateRecords[selectable] = state.position.pixels; - } - } - - @override - void dispose() { - _selectableStartEdgeUpdateRecords.clear(); - _selectableEndEdgeUpdateRecords.clear(); - _scheduledLayoutChange = false; - _autoScroller.stopAutoScroll(); - super.dispose(); - } -} - -Offset _getDeltaToScrollOrigin(ScrollableState scrollableState) { - return switch (scrollableState.axisDirection) { - AxisDirection.up => Offset(0, -scrollableState.position.pixels), - AxisDirection.down => Offset(0, scrollableState.position.pixels), - AxisDirection.left => Offset(-scrollableState.position.pixels, 0), - AxisDirection.right => Offset(scrollableState.position.pixels, 0), - }; -} - -/// With [_ScrollSemantics] certain child [SemanticsNode]s can be -/// excluded from the scrollable area for semantics purposes. -/// -/// Nodes, that are to be excluded, have to be tagged with -/// [RenderViewport.excludeFromScrolling] and the [RenderAbstractViewport] in -/// use has to add the [RenderViewport.useTwoPaneSemantics] tag to its -/// [SemanticsConfiguration] by overriding -/// [RenderObject.describeSemanticsConfiguration]. -/// -/// If the tag [RenderViewport.useTwoPaneSemantics] is present on the viewport, -/// two semantics nodes will be used to represent the [Scrollable]: The outer -/// node will contain all children, that are excluded from scrolling. The inner -/// node, which is annotated with the scrolling actions, will house the -/// scrollable children. -class _ScrollSemantics extends SingleChildRenderObjectWidget { - const _ScrollSemantics({ - super.key, - required this.position, - required this.allowImplicitScrolling, - required this.axis, - required this.semanticChildCount, - super.child, - }) : assert(semanticChildCount == null || semanticChildCount >= 0); - - final ScrollPosition position; - final bool allowImplicitScrolling; - final int? semanticChildCount; - final Axis axis; - - @override - _RenderScrollSemantics createRenderObject(BuildContext context) { - return _RenderScrollSemantics( - position: position, - allowImplicitScrolling: allowImplicitScrolling, - semanticChildCount: semanticChildCount, - axis: axis, - ); - } - - @override - void updateRenderObject( - BuildContext context, - _RenderScrollSemantics renderObject, - ) { - renderObject - ..allowImplicitScrolling = allowImplicitScrolling - ..axis = axis - ..position = position - ..semanticChildCount = semanticChildCount; - } -} - -class _RenderScrollSemantics extends RenderProxyBox { - _RenderScrollSemantics({ - required ScrollPosition position, - required bool allowImplicitScrolling, - required this.axis, - required int? semanticChildCount, - RenderBox? child, - }) : _position = position, - _allowImplicitScrolling = allowImplicitScrolling, - _semanticChildCount = semanticChildCount, - super(child) { - position.addListener(markNeedsSemanticsUpdate); - } - - /// Whether this render object is excluded from the semantic tree. - ScrollPosition get position => _position; - ScrollPosition _position; - set position(ScrollPosition value) { - if (value == _position) { - return; - } - _position.removeListener(markNeedsSemanticsUpdate); - _position = value; - _position.addListener(markNeedsSemanticsUpdate); - markNeedsSemanticsUpdate(); - } - - /// Whether this node can be scrolled implicitly. - bool get allowImplicitScrolling => _allowImplicitScrolling; - bool _allowImplicitScrolling; - set allowImplicitScrolling(bool value) { - if (value == _allowImplicitScrolling) { - return; - } - _allowImplicitScrolling = value; - markNeedsSemanticsUpdate(); - } - - Axis axis; - - int? get semanticChildCount => _semanticChildCount; - int? _semanticChildCount; - set semanticChildCount(int? value) { - if (value == semanticChildCount) { - return; - } - _semanticChildCount = value; - markNeedsSemanticsUpdate(); - } - - void _onScrollToOffset(Offset targetOffset) { - final double offset = switch (axis) { - Axis.horizontal => targetOffset.dx, - Axis.vertical => targetOffset.dy, - }; - _position.jumpTo(offset); - } - - @override - void describeSemanticsConfiguration(SemanticsConfiguration config) { - super.describeSemanticsConfiguration(config); - config.isSemanticBoundary = true; - if (position.haveDimensions) { - config - ..hasImplicitScrolling = allowImplicitScrolling - ..scrollPosition = _position.pixels - ..scrollExtentMax = _position.maxScrollExtent - ..scrollExtentMin = _position.minScrollExtent - ..scrollChildCount = semanticChildCount; - if (position.maxScrollExtent > position.minScrollExtent && - allowImplicitScrolling) { - config.onScrollToOffset = _onScrollToOffset; - } - } - } - - SemanticsNode? _innerNode; - - @override - void assembleSemanticsNode( - SemanticsNode node, - SemanticsConfiguration config, - Iterable children, - ) { - if (children.isEmpty || - !children.first.isTagged(RenderViewport.useTwoPaneSemantics)) { - _innerNode = null; - super.assembleSemanticsNode(node, config, children); - return; - } - - (_innerNode ??= SemanticsNode(showOnScreen: showOnScreen)).rect = node.rect; - - int? firstVisibleIndex; - final excluded = [_innerNode!]; - final included = []; - for (final child in children) { - assert(child.isTagged(RenderViewport.useTwoPaneSemantics)); - if (child.isTagged(RenderViewport.excludeFromScrolling)) { - excluded.add(child); - } else { - if (!child.flagsCollection.isHidden) { - firstVisibleIndex ??= child.indexInParent; - } - included.add(child); - } - } - config.scrollIndex = firstVisibleIndex; - node.updateWith(config: null, childrenInInversePaintOrder: excluded); - _innerNode!.updateWith( - config: config, - childrenInInversePaintOrder: included, - ); - } - - @override - void clearSemantics() { - super.clearSemantics(); - _innerNode = null; - } -} - -// Not using a RestorableDouble because we want to allow null values and override -// [enabled]. -class _RestorableScrollOffset extends RestorableValue { - @override - double? createDefaultValue() => null; - - @override - void didUpdateValue(double? oldValue) { - notifyListeners(); - } - - @override - double fromPrimitives(Object? data) { - return data! as double; - } - - @override - Object? toPrimitives() { - return value; - } - - @override - bool get enabled => value != null; -} diff --git a/lib/common/widgets/flutter/scroll_view/scrollable_helpers.dart b/lib/common/widgets/flutter/scroll_view/scrollable_helpers.dart deleted file mode 100644 index 856d19834..000000000 --- a/lib/common/widgets/flutter/scroll_view/scrollable_helpers.dart +++ /dev/null @@ -1,208 +0,0 @@ -// Copyright 2014 The Flutter Authors. All rights reserved. -// Use of this source code is governed by a BSD-style license that can be -// found in the LICENSE file. - -/// @docImport 'package:flutter/material.dart'; -/// -/// @docImport 'overscroll_indicator.dart'; -/// @docImport 'viewport.dart'; - -// ignore_for_file: dangling_library_doc_comments - -import 'dart:math' as math; - -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scrollable.dart'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart' - hide EdgeDraggingAutoScroller, Scrollable, ScrollableState; - -/// An auto scroller that scrolls the [scrollable] if a drag gesture drags close -/// to its edge. -/// -/// The scroll velocity is controlled by the [velocityScalar]: -/// -/// velocity = (distance of overscroll) * [velocityScalar]. -class EdgeDraggingAutoScroller { - /// Creates a auto scroller that scrolls the [scrollable]. - EdgeDraggingAutoScroller( - this.scrollable, { - this.onScrollViewScrolled, - required this.velocityScalar, - }); - - /// The [Scrollable] this auto scroller is scrolling. - final ScrollableState scrollable; - - /// Called when a scroll view is scrolled. - /// - /// The scroll view may be scrolled multiple times in a row until the drag - /// target no longer triggers the auto scroll. This callback will be called - /// in between each scroll. - final VoidCallback? onScrollViewScrolled; - - /// {@template flutter.widgets.EdgeDraggingAutoScroller.velocityScalar} - /// The velocity scalar per pixel over scroll. - /// - /// It represents how the velocity scale with the over scroll distance. The - /// auto-scroll velocity = (distance of overscroll) * velocityScalar. - /// {@endtemplate} - final double velocityScalar; - - late Rect _dragTargetRelatedToScrollOrigin; - - /// Whether the auto scroll is in progress. - bool get scrolling => _scrolling; - bool _scrolling = false; - - double _offsetExtent(Offset offset, Axis scrollDirection) { - return switch (scrollDirection) { - Axis.horizontal => offset.dx, - Axis.vertical => offset.dy, - }; - } - - double _sizeExtent(Size size, Axis scrollDirection) { - return switch (scrollDirection) { - Axis.horizontal => size.width, - Axis.vertical => size.height, - }; - } - - AxisDirection get _axisDirection => scrollable.axisDirection; - Axis get _scrollDirection => axisDirectionToAxis(_axisDirection); - - /// Starts the auto scroll if the [dragTarget] is close to the edge. - /// - /// The scroll starts to scroll the [scrollable] if the target rect is close - /// to the edge of the [scrollable]; otherwise, it remains stationary. - /// - /// If the scrollable is already scrolling, calling this method updates the - /// previous dragTarget to the new value and continues scrolling if necessary. - void startAutoScrollIfNecessary(Rect dragTarget) { - final Offset deltaToOrigin = scrollable.deltaToScrollOrigin; - _dragTargetRelatedToScrollOrigin = dragTarget.translate( - deltaToOrigin.dx, - deltaToOrigin.dy, - ); - if (_scrolling) { - // The change will be picked up in the next scroll. - return; - } - assert(!_scrolling); - _scroll(); - } - - /// Stop any ongoing auto scrolling. - void stopAutoScroll() { - _scrolling = false; - } - - Future _scroll() async { - final scrollRenderBox = scrollable.context.findRenderObject()! as RenderBox; - final Matrix4 transform = scrollRenderBox.getTransformTo(null); - final Rect globalRect = MatrixUtils.transformRect( - transform, - Rect.fromLTRB( - 0, - 0, - scrollRenderBox.size.width, - scrollRenderBox.size.height, - ), - ); - final Rect transformedDragTarget = MatrixUtils.transformRect( - transform, - _dragTargetRelatedToScrollOrigin, - ); - - assert( - (globalRect.size.width + precisionErrorTolerance) >= - transformedDragTarget.size.width && - (globalRect.size.height + precisionErrorTolerance) >= - transformedDragTarget.size.height, - 'Drag target size is larger than scrollable size, which may cause bouncing', - ); - _scrolling = true; - double? newOffset; - const overDragMax = 20.0; - - final Offset deltaToOrigin = scrollable.deltaToScrollOrigin; - final Offset viewportOrigin = globalRect.topLeft.translate( - deltaToOrigin.dx, - deltaToOrigin.dy, - ); - final double viewportStart = _offsetExtent( - viewportOrigin, - _scrollDirection, - ); - final double viewportEnd = - viewportStart + _sizeExtent(globalRect.size, _scrollDirection); - - final double proxyStart = _offsetExtent( - _dragTargetRelatedToScrollOrigin.topLeft, - _scrollDirection, - ); - final double proxyEnd = _offsetExtent( - _dragTargetRelatedToScrollOrigin.bottomRight, - _scrollDirection, - ); - switch (_axisDirection) { - case AxisDirection.up: - case AxisDirection.left: - if (proxyEnd > viewportEnd && - scrollable.position.pixels > scrollable.position.minScrollExtent) { - final double overDrag = math.min(proxyEnd - viewportEnd, overDragMax); - newOffset = math.max( - scrollable.position.minScrollExtent, - scrollable.position.pixels - overDrag, - ); - } else if (proxyStart < viewportStart && - scrollable.position.pixels < scrollable.position.maxScrollExtent) { - final double overDrag = math.min( - viewportStart - proxyStart, - overDragMax, - ); - newOffset = math.min( - scrollable.position.maxScrollExtent, - scrollable.position.pixels + overDrag, - ); - } - case AxisDirection.right: - case AxisDirection.down: - if (proxyStart < viewportStart && - scrollable.position.pixels > scrollable.position.minScrollExtent) { - final double overDrag = math.min( - viewportStart - proxyStart, - overDragMax, - ); - newOffset = math.max( - scrollable.position.minScrollExtent, - scrollable.position.pixels - overDrag, - ); - } else if (proxyEnd > viewportEnd && - scrollable.position.pixels < scrollable.position.maxScrollExtent) { - final double overDrag = math.min(proxyEnd - viewportEnd, overDragMax); - newOffset = math.min( - scrollable.position.maxScrollExtent, - scrollable.position.pixels + overDrag, - ); - } - } - - if (newOffset == null || - (newOffset - scrollable.position.pixels).abs() < 1.0) { - // Drag should not trigger scroll. - _scrolling = false; - return; - } - final duration = Duration(milliseconds: (1000 / velocityScalar).round()); - await scrollable.position.animateTo( - newOffset, - duration: duration, - curve: Curves.linear, - ); - onScrollViewScrolled?.call(); - if (_scrolling) { - await _scroll(); - } - } -} diff --git a/lib/common/widgets/gesture/vertical_drag_gesture_recognizer.dart b/lib/common/widgets/gesture/vertical_drag_gesture_recognizer.dart deleted file mode 100644 index 1c0e58995..000000000 --- a/lib/common/widgets/gesture/vertical_drag_gesture_recognizer.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:flutter/gestures.dart' - show VerticalDragGestureRecognizer, PointerEvent, RecognizerCallback; - -typedef IsDyAllowed = bool Function(double dy); - -class CustomVerticalDragGestureRecognizer - extends VerticalDragGestureRecognizer { - CustomVerticalDragGestureRecognizer({ - super.debugOwner, - super.supportedDevices, - super.allowedButtonsFilter, - }); - - IsDyAllowed? isDyAllowed; - - bool _isDyAllowed = true; - - @override - bool isPointerAllowed(PointerEvent event) { - _isDyAllowed = isDyAllowed?.call(event.localPosition.dy) ?? true; - return super.isPointerAllowed(event); - } - - @override - T? invokeCallback( - String name, - RecognizerCallback callback, { - String Function()? debugReport, - }) { - if (!_isDyAllowed) return null; - return super.invokeCallback(name, callback, debugReport: debugReport); - } - - @override - void dispose() { - isDyAllowed = null; - super.dispose(); - } -} diff --git a/lib/common/widgets/loading_widget/loading_widget.dart b/lib/common/widgets/loading_widget/loading_widget.dart index 932bf9f87..d1df73e60 100644 --- a/lib/common/widgets/loading_widget/loading_widget.dart +++ b/lib/common/widgets/loading_widget/loading_widget.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/m3e_loading_indicator.dart'; import 'package:flutter/material.dart'; @@ -9,13 +8,13 @@ const Widget linearLoading = SliverToBoxAdapter( child: LinearProgressIndicator(), ); -const Widget scrollableError = customScrollView(slivers: [HttpError()]); +const Widget scrollableError = CustomScrollView(slivers: [HttpError()]); Widget scrollErrorWidget({ String? errMsg, VoidCallback? onReload, ScrollController? controller, -}) => customScrollView( +}) => CustomScrollView( controller: controller, slivers: [ HttpError( diff --git a/lib/pages/about/view.dart b/lib/pages/about/view.dart index 7d2edf6e1..29ee5b55e 100644 --- a/lib/pages/about/view.dart +++ b/lib/pages/about/view.dart @@ -8,7 +8,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/dialog/export_import.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/mine/controller.dart'; import 'package:PiliPlus/services/logger.dart'; import 'package:PiliPlus/utils/accounts.dart'; @@ -91,7 +90,7 @@ class _AboutPageState extends State { return Scaffold( appBar: showAppBar ? AppBar(title: const Text('关于')) : null, resizeToAvoidBottomInset: false, - body: listView( + body: ListView( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/article/view.dart b/lib/pages/article/view.dart index 936c424ef..5d92d25f1 100644 --- a/lib/pages/article/view.dart +++ b/lib/pages/article/view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; @@ -84,7 +83,7 @@ class _ArticlePageState extends CommonDynPageState { if (isPortrait) { return Padding( padding: EdgeInsets.symmetric(horizontal: padding), - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -113,7 +112,7 @@ class _ArticlePageState extends CommonDynPageState { children: [ Expanded( flex: flex, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -145,7 +144,7 @@ class _ArticlePageState extends CommonDynPageState { resizeToAvoidBottomInset: false, body: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/article_list/view.dart b/lib/pages/article_list/view.dart index 90b8d9342..77c2d863e 100644 --- a/lib/pages/article_list/view.dart +++ b/lib/pages/article_list/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/constants.dart'; @@ -39,7 +38,7 @@ class _ArticleListPageState extends State with GridMixin { color: theme.colorScheme.surface, child: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ Obx(() => _buildHeader(theme, _controller.list.value)), diff --git a/lib/pages/audio/view.dart b/lib/pages/audio/view.dart index 92acfb053..de5ffc288 100644 --- a/lib/pages/audio/view.dart +++ b/lib/pages/audio/view.dart @@ -4,7 +4,6 @@ import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image_viewer/hero.dart'; @@ -203,7 +202,7 @@ class _AudioPageState extends State { builder: (context) { final theme = Theme.of(context); final colorScheme = theme.colorScheme; - Widget child = customScrollView( + Widget child = CustomScrollView( controller: scrollController, physics: _controller.reachStart ? null diff --git a/lib/pages/blacklist/view.dart b/lib/pages/blacklist/view.dart index a36ad9b7f..584e07bc2 100644 --- a/lib/pages/blacklist/view.dart +++ b/lib/pages/blacklist/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -46,7 +45,7 @@ class _BlackListPageState extends State { ), body: refreshIndicator( onRefresh: _blackListController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _blackListController.scrollController, slivers: [ diff --git a/lib/pages/bubble/view.dart b/lib/pages/bubble/view.dart index 95fb88b35..159ece5ca 100644 --- a/lib/pages/bubble/view.dart +++ b/lib/pages/bubble/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; @@ -55,7 +54,7 @@ class _BubblePageState extends State final padding = MediaQuery.viewPaddingOf(context); Widget child = refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _controller.scrollController, slivers: [ diff --git a/lib/pages/common/search/common_search_page.dart b/lib/pages/common/search/common_search_page.dart index 6e7e029b6..3855836e5 100644 --- a/lib/pages/common/search/common_search_page.dart +++ b/lib/pages/common/search/common_search_page.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -39,7 +38,7 @@ abstract class CommonSearchPageState Widget _build(bool multiSelect) { return Scaffold( appBar: _buildBar(multiSelect), - body: customScrollView( + body: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, slivers: [ diff --git a/lib/pages/danmaku_block/view.dart b/lib/pages/danmaku_block/view.dart index e9d54b770..6e4e349de 100644 --- a/lib/pages/danmaku_block/view.dart +++ b/lib/pages/danmaku_block/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; @@ -85,7 +84,7 @@ class _DanmakuBlockPageState extends State { if (list.isEmpty) { return scrollableError; } - return ExtendedListView.builder( + return ListView.builder( itemCount: list.length, padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 100, diff --git a/lib/pages/dlna/view.dart b/lib/pages/dlna/view.dart index d5ba978dd..39ed53944 100644 --- a/lib/pages/dlna/view.dart +++ b/lib/pages/dlna/view.dart @@ -1,6 +1,5 @@ import 'dart:async'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; @@ -84,7 +83,7 @@ class _DLNAPageState extends State { const SizedBox(width: 6), ], ), - body: customScrollView( + body: CustomScrollView( slivers: [ if (_isSearching) linearLoading, ViewSliverSafeArea(sliver: _buildBody(colorScheme)), diff --git a/lib/pages/download/detail/view.dart b/lib/pages/download/detail/view.dart index a19520d93..be1312dda 100644 --- a/lib/pages/download/detail/view.dart +++ b/lib/pages/download/detail/view.dart @@ -3,7 +3,6 @@ import 'dart:async'; import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; @@ -144,7 +143,7 @@ class _DownloadDetailPageState extends State ], ), ), - body: customScrollView( + body: CustomScrollView( slivers: [ ViewSliverSafeArea( sliver: Obx(() { diff --git a/lib/pages/download/downloading/view.dart b/lib/pages/download/downloading/view.dart index c55aa2dee..001da6ea9 100644 --- a/lib/pages/download/downloading/view.dart +++ b/lib/pages/download/downloading/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/models_new/download/bili_download_entry_info.dart'; @@ -64,7 +63,7 @@ class _DownloadingPageState extends State ], ), ), - body: customScrollView( + body: CustomScrollView( slivers: [ ViewSliverSafeArea( sliver: Obx(() { diff --git a/lib/pages/download/view.dart b/lib/pages/download/view.dart index 9d2e238ea..b743e2040 100644 --- a/lib/pages/download/view.dart +++ b/lib/pages/download/view.dart @@ -6,7 +6,6 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/layout_builder.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/select_mask.dart'; @@ -123,7 +122,7 @@ class _DownloadPageState extends State { ), body: Padding( padding: EdgeInsets.only(left: padding.left, right: padding.right), - child: customScrollView( + child: CustomScrollView( slivers: [ Obx(() { final entry = diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index a5021275a..8a53c6ca6 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/assets.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart'; import 'package:PiliPlus/models/common/image_type.dart'; @@ -42,7 +41,7 @@ class _UpPanelState extends State { final upData = controller.upState.value.data; final List upList = upData.upList; final List? liveList = upData.liveUsers?.items; - return customScrollView( + return CustomScrollView( scrollDirection: isTop ? Axis.horizontal : Axis.vertical, physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, diff --git a/lib/pages/dynamics_create_vote/view.dart b/lib/pages/dynamics_create_vote/view.dart index 1e476bc6b..f7610a54d 100644 --- a/lib/pages/dynamics_create_vote/view.dart +++ b/lib/pages/dynamics_create_vote/view.dart @@ -1,7 +1,6 @@ import 'dart:io' show File; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/time_picker.dart'; import 'package:PiliPlus/models/dynamics/vote_model.dart'; @@ -58,7 +57,7 @@ class _CreateVotePageState extends State { appBar: AppBar( title: Text('${_controller.voteId != null ? '' : '发起'}投票'), ), - body: listView( + body: ListView( padding: EdgeInsets.only( left: padding.left + 16, right: padding.right + 16, diff --git a/lib/pages/dynamics_detail/view.dart b/lib/pages/dynamics_detail/view.dart index 42d8fbbfb..f6080dbea 100644 --- a/lib/pages/dynamics_detail/view.dart +++ b/lib/pages/dynamics_detail/view.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/flutter/text_field/controller.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/http/constants.dart'; @@ -249,7 +248,7 @@ class _DynamicDetailPageState extends CommonDynPageState { if (isPortrait) { child = Padding( padding: EdgeInsets.symmetric(horizontal: padding), - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -276,7 +275,7 @@ class _DynamicDetailPageState extends CommonDynPageState { children: [ Expanded( flex: flex, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -308,7 +307,7 @@ class _DynamicDetailPageState extends CommonDynPageState { resizeToAvoidBottomInset: false, body: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/dynamics_mention/view.dart b/lib/pages/dynamics_mention/view.dart index a1666fc67..3bd8f679a 100644 --- a/lib/pages/dynamics_mention/view.dart +++ b/lib/pages/dynamics_mention/view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/flutter/draggable_sheet/draggable_scrollable_sheet_topic.dart' as topic_sheet; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_header.dart'; @@ -185,7 +184,7 @@ class _DynMentionPanelState } return false; }, - child: customScrollView( + child: CustomScrollView( controller: widget.scrollController, slivers: [ Obx( diff --git a/lib/pages/dynamics_select_topic/view.dart b/lib/pages/dynamics_select_topic/view.dart index 6443a3978..1d9bd60c1 100644 --- a/lib/pages/dynamics_select_topic/view.dart +++ b/lib/pages/dynamics_select_topic/view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/flutter/draggable_sheet/draggable_scrollable_sheet_topic.dart' as topic_sheet; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/dynamic/dyn_topic_top/topic_item.dart'; @@ -192,7 +191,7 @@ class _SelectTopicPanelState Loading() => m3eLoading, Success?>(:final response) => response != null && response.isNotEmpty - ? ExtendedListView.builder( + ? ListView.builder( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 100, ), diff --git a/lib/pages/dynamics_tab/view.dart b/lib/pages/dynamics_tab/view.dart index d63b0a00b..c14c2e08b 100644 --- a/lib/pages/dynamics_tab/view.dart +++ b/lib/pages/dynamics_tab/view.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/dynamic/dynamics_type.dart'; @@ -71,7 +70,7 @@ class _DynamicsTabPageState extends State dynamicsController.queryFollowUp(); return controller.onRefresh(); }, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, slivers: [ diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index e42fa51d1..544046c85 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/dynamic_sliver_app_bar.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; @@ -67,7 +66,7 @@ class _DynTopicPageState extends State with DynMixin { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/dynamics_topic_rcmd/view.dart b/lib/pages/dynamics_topic_rcmd/view.dart index fe3ad6119..f80c09806 100644 --- a/lib/pages/dynamics_topic_rcmd/view.dart +++ b/lib/pages/dynamics_topic_rcmd/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; @@ -27,7 +26,7 @@ class _DynTopicRcmdPageState extends State { appBar: AppBar(title: const Text('话题')), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ ViewSliverSafeArea( diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart index 8a6adfd83..ee082b0a3 100644 --- a/lib/pages/episode_panel/view.dart +++ b/lib/pages/episode_panel/view.dart @@ -5,7 +5,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; @@ -281,7 +280,7 @@ class _EpisodePanelState extends State ) { final isCurrTab = tabIndex == widget.initialTabIndex; return KeepAliveWrapper( - child: customScrollView( + child: CustomScrollView( reverse: _isReversed[tabIndex], physics: const AlwaysScrollableScrollPhysics(), controller: _itemScrollController[tabIndex], diff --git a/lib/pages/fav/article/view.dart b/lib/pages/fav/article/view.dart index dacc27df7..f2b74a017 100644 --- a/lib/pages/fav/article/view.dart +++ b/lib/pages/fav/article/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fav/fav_article/item.dart'; @@ -31,7 +30,7 @@ class _FavArticlePageState extends State super.build(context); return refreshIndicator( onRefresh: _favArticleController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _favArticleController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav/cheese/view.dart b/lib/pages/fav/cheese/view.dart index aef8bbf6a..c41616520 100644 --- a/lib/pages/fav/cheese/view.dart +++ b/lib/pages/fav/cheese/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_cheese/item.dart'; @@ -30,7 +29,7 @@ class _FavCheesePageState extends State final ThemeData theme = Theme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav/note/child_view.dart b/lib/pages/fav/note/child_view.dart index 0318f6a7c..4c9efa84e 100644 --- a/lib/pages/fav/note/child_view.dart +++ b/lib/pages/fav/note/child_view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fav/fav_note/list.dart'; @@ -44,7 +43,7 @@ class _FavNoteChildPageState extends State children: [ refreshIndicator( onRefresh: _favNoteController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _favNoteController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav/pgc/child_view.dart b/lib/pages/fav/pgc/child_view.dart index 6b18f4693..0f0f43e65 100644 --- a/lib/pages/fav/pgc/child_view.dart +++ b/lib/pages/fav/pgc/child_view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/fav_pgc_item.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fav/fav_pgc/list.dart'; @@ -50,7 +49,7 @@ class _FavPgcChildPageState extends State children: [ refreshIndicator( onRefresh: _favPgcController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _favPgcController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav/topic/view.dart b/lib/pages/fav/topic/view.dart index 7b3718e33..69f75c3c6 100644 --- a/lib/pages/fav/topic/view.dart +++ b/lib/pages/fav/topic/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart' show m3eLoading; @@ -34,7 +33,7 @@ class _FavTopicPageState extends State final ThemeData theme = Theme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav/video/view.dart b/lib/pages/fav/video/view.dart index 75a66938b..f37ff43ca 100644 --- a/lib/pages/fav/video/view.dart +++ b/lib/pages/fav/video/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fav/fav_folder/list.dart'; @@ -29,7 +28,7 @@ class _FavVideoPageState extends State super.build(context); return refreshIndicator( onRefresh: _favController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _favController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index d4cea32a2..a083e49cc 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/fav.dart'; @@ -101,7 +100,7 @@ class _FavDetailPageState extends State with GridMixin { ), body: refreshIndicator( onRefresh: _favDetailController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _favDetailController.scrollController, slivers: [ diff --git a/lib/pages/fav_panel/view.dart b/lib/pages/fav_panel/view.dart index 818113e89..bb2fc822f 100644 --- a/lib/pages/fav_panel/view.dart +++ b/lib/pages/fav_panel/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/fav/fav_folder/list.dart'; @@ -43,7 +42,7 @@ class _FavPanelState extends State { late final list = widget.ctr.favFolderData.value.list!; return switch (loadingState) { Loading() => m3eLoading, - Success() => ExtendedListView.builder( + Success() => ListView.builder( controller: widget.scrollController, itemCount: list.length, itemBuilder: (context, index) { diff --git a/lib/pages/follow/child/child_view.dart b/lib/pages/follow/child/child_view.dart index 48bbf5693..649bb6d8d 100644 --- a/lib/pages/follow/child/child_view.dart +++ b/lib/pages/follow/child/child_view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/button/more_btn.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/follow_order_type.dart'; @@ -59,7 +58,7 @@ class _FollowChildPageState extends State padding: EdgeInsets.only(left: padding.left, right: padding.right), child: refreshIndicator( onRefresh: _followController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _followController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/follow_type/view.dart b/lib/pages/follow_type/view.dart index 42b8f7ecf..1fa199ae6 100644 --- a/lib/pages/follow_type/view.dart +++ b/lib/pages/follow_type/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -25,7 +24,7 @@ abstract class FollowTypePageState extends State { appBar: appBar, body: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), // controller: controller.scrollController, slivers: [ diff --git a/lib/pages/group_panel/view.dart b/lib/pages/group_panel/view.dart index 7e547ca23..921e41e25 100644 --- a/lib/pages/group_panel/view.dart +++ b/lib/pages/group_panel/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/member.dart'; @@ -70,7 +69,7 @@ class _GroupPanelState extends State { Widget get _buildBody { return switch (loadingState) { Loading() => m3eLoading, - Success(:final response) => ExtendedListView.builder( + Success(:final response) => ListView.builder( controller: widget.scrollController, itemCount: response.length, itemBuilder: (context, index) { diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index 55c6e4645..d8ba6540c 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/widgets/appbar/appbar.dart'; import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -63,7 +62,7 @@ class _HistoryPageState extends State final padding = MediaQuery.viewPaddingOf(context); Widget child = refreshIndicator( onRefresh: _historyController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _historyController.scrollController, slivers: [ diff --git a/lib/pages/hot/view.dart b/lib/pages/hot/view.dart index b1cfcefdc..472dad6b0 100644 --- a/lib/pages/hot/view.dart +++ b/lib/pages/hot/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_h.dart'; @@ -61,7 +60,7 @@ class _HotPageState extends State super.build(context); return refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: controller.scrollController, slivers: [ diff --git a/lib/pages/later/child_view.dart b/lib/pages/later/child_view.dart index 83f05a9c5..02b84140e 100644 --- a/lib/pages/later/child_view.dart +++ b/lib/pages/later/child_view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/later_view_type.dart'; @@ -45,7 +44,7 @@ class _LaterViewChildPageState extends State super.build(context); return refreshIndicator( onRefresh: _laterController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), controller: _laterController.scrollController, slivers: [ diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart index e9ed00a94..3fe46b972 100644 --- a/lib/pages/live/view.dart +++ b/lib/pages/live/view.dart @@ -3,7 +3,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/button/more_btn.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; @@ -56,7 +55,7 @@ class _LivePageState extends State decoration: const BoxDecoration(borderRadius: Style.mdRadius), child: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/live_area_detail/child/view.dart b/lib/pages/live_area_detail/child/view.dart index 7d6337298..04d84bda6 100644 --- a/lib/pages/live_area_detail/child/view.dart +++ b/lib/pages/live_area_detail/child/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -48,7 +47,7 @@ class _LiveAreaChildPageState extends State final ThemeData theme = Theme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/live_follow/view.dart b/lib/pages/live_follow/view.dart index ea3b4ea5d..0ea623ebb 100644 --- a/lib/pages/live_follow/view.dart +++ b/lib/pages/live_follow/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/live/live_follow/item.dart'; @@ -36,7 +35,7 @@ class _LiveFollowPageState extends State { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/live_room/contribution_rank/view.dart b/lib/pages/live_room/contribution_rank/view.dart index d9108adc9..b29e6d144 100644 --- a/lib/pages/live_room/contribution_rank/view.dart +++ b/lib/pages/live_room/contribution_rank/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; @@ -132,7 +131,7 @@ class _ContributionRankTypeState extends State<_ContributionRankType> type: .transparency, child: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/live_search/child/view.dart b/lib/pages/live_search/child/view.dart index d74e05cdb..2c4447022 100644 --- a/lib/pages/live_search/child/view.dart +++ b/lib/pages/live_search/child/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/live/live_search_type.dart'; @@ -38,7 +37,7 @@ class _LiveSearchChildPageState extends State double padding = widget.searchType == LiveSearchType.room ? 12 : 0; return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/log_table/view.dart b/lib/pages/log_table/view.dart index 2fbdac72d..f1d0658d3 100644 --- a/lib/pages/log_table/view.dart +++ b/lib/pages/log_table/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -23,7 +22,7 @@ class _LogPageState extends State> { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar(title: Text(_controller.title)), - body: customScrollView( + body: CustomScrollView( slivers: [ SliverPadding( padding: EdgeInsets.only( diff --git a/lib/pages/login_devices/view.dart b/lib/pages/login_devices/view.dart index 41354d04c..1c130f119 100644 --- a/lib/pages/login_devices/view.dart +++ b/lib/pages/login_devices/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -28,7 +27,7 @@ class LoginDevicesPageState extends State { appBar: AppBar(title: const Text('登录设备')), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ ViewSliverSafeArea( diff --git a/lib/pages/main_reply/view.dart b/lib/pages/main_reply/view.dart index 113ad83ed..40b305c10 100644 --- a/lib/pages/main_reply/view.dart +++ b/lib/pages/main_reply/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; @@ -78,7 +77,7 @@ class _MainReplyPageState extends State left: padding.left, right: padding.right, ), - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ buildReplyHeader(colorScheme), diff --git a/lib/pages/match_info/view.dart b/lib/pages/match_info/view.dart index 9b550cf4e..c903a4456 100644 --- a/lib/pages/match_info/view.dart +++ b/lib/pages/match_info/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' @@ -48,7 +47,7 @@ class _MatchInfoPageState extends CommonDynPageState { body: ViewSafeArea( child: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/member/widget/medal_wall.dart b/lib/pages/member/widget/medal_wall.dart index 659800afa..3a0fcfafc 100644 --- a/lib/pages/member/widget/medal_wall.dart +++ b/lib/pages/member/widget/medal_wall.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/assets.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; import 'package:PiliPlus/models_new/live/live_medal_wall/data.dart'; @@ -23,7 +22,7 @@ class MedalWall extends StatelessWidget { title: const Text('粉丝勋章墙'), contentPadding: const .symmetric(vertical: 16), constraints: const BoxConstraints.tightFor(width: 380), - content: customScrollView( + content: CustomScrollView( shrinkWrap: true, slivers: [ SliverToBoxAdapter( diff --git a/lib/pages/member_article/view.dart b/lib/pages/member_article/view.dart index 1175332aa..ef04dac70 100644 --- a/lib/pages/member_article/view.dart +++ b/lib/pages/member_article/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_article/item.dart'; @@ -44,7 +43,7 @@ class _MemberArticleState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_audio/view.dart b/lib/pages/member_audio/view.dart index 8990f6f89..78ce6f192 100644 --- a/lib/pages/member_audio/view.dart +++ b/lib/pages/member_audio/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; @@ -45,7 +44,7 @@ class _MemberAudioState extends State final colorScheme = ColorScheme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_cheese/view.dart b/lib/pages/member_cheese/view.dart index 150662444..543924f9a 100644 --- a/lib/pages/member_cheese/view.dart +++ b/lib/pages/member_cheese/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_cheese/item.dart'; @@ -41,7 +40,7 @@ class _MemberCheeseState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_coin_arc/view.dart b/lib/pages/member_coin_arc/view.dart index 059ad9670..43de1ecab 100644 --- a/lib/pages/member_coin_arc/view.dart +++ b/lib/pages/member_coin_arc/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart'; @@ -52,7 +51,7 @@ class _MemberCoinArcPageState extends State { ), body: refreshIndicator( onRefresh: _ctr.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_comic/view.dart b/lib/pages/member_comic/view.dart index 5e7c995db..d1a177b0b 100644 --- a/lib/pages/member_comic/view.dart +++ b/lib/pages/member_comic/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_archive/item.dart'; @@ -41,7 +40,7 @@ class _MemberComicState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_dynamics/view.dart b/lib/pages/member_dynamics/view.dart index 3f32a5d12..a24619ddd 100644 --- a/lib/pages/member_dynamics/view.dart +++ b/lib/pages/member_dynamics/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; @@ -62,7 +61,7 @@ class _MemberDynamicsPageState extends State Widget _buildBody(EdgeInsets padding) => refreshIndicator( onRefresh: _memberDynamicController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_favorite/view.dart b/lib/pages/member_favorite/view.dart index 9e418f44a..599f33eae 100644 --- a/lib/pages/member_favorite/view.dart +++ b/lib/pages/member_favorite/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_header.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -47,7 +46,7 @@ class _MemberFavoriteState extends State final theme = Theme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: _FavScrollPhysics(controller: _controller), slivers: [ SliverPadding( diff --git a/lib/pages/member_guard/view.dart b/lib/pages/member_guard/view.dart index 992f55c4b..f3c49db11 100644 --- a/lib/pages/member_guard/view.dart +++ b/lib/pages/member_guard/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; @@ -61,7 +60,7 @@ class _MemberGuardState extends State { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( slivers: [ ViewSliverSafeArea( sliver: Obx(() => _buildBody(_controller.loadingState.value)), diff --git a/lib/pages/member_home/view.dart b/lib/pages/member_home/view.dart index 067fe756b..d8c6e3acc 100644 --- a/lib/pages/member_home/view.dart +++ b/lib/pages/member_home/view.dart @@ -2,7 +2,6 @@ import 'dart:math'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/button/more_btn.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space/data.dart'; @@ -77,7 +76,7 @@ class _MemberHomeState extends State Loading() => m3eLoading, Success(response: final res) => res != null - ? customScrollView( + ? CustomScrollView( slivers: [ if (res.archive?.item?.isNotEmpty == true) ...[ _header( diff --git a/lib/pages/member_like_arc/view.dart b/lib/pages/member_like_arc/view.dart index 4d6aa0f4a..48ae86c2c 100644 --- a/lib/pages/member_like_arc/view.dart +++ b/lib/pages/member_like_arc/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/member/coin_like_arc/item.dart'; @@ -52,7 +51,7 @@ class _MemberLikeArcPageState extends State { ), body: refreshIndicator( onRefresh: _ctr.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_opus/view.dart b/lib/pages/member_opus/view.dart index b414b7950..bbc67d92b 100644 --- a/lib/pages/member_opus/view.dart +++ b/lib/pages/member_opus/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/space_opus.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_opus/item.dart'; @@ -54,7 +53,7 @@ class _MemberOpusState extends State children: [ refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_pgc/view.dart b/lib/pages/member_pgc/view.dart index 7bab72de6..1280415b7 100644 --- a/lib/pages/member_pgc/view.dart +++ b/lib/pages/member_pgc/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_archive/item.dart'; @@ -48,7 +47,7 @@ class _MemberBangumiState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_profile/view.dart b/lib/pages/member_profile/view.dart index 527a8b42c..fa4082b48 100644 --- a/lib/pages/member_profile/view.dart +++ b/lib/pages/member_profile/view.dart @@ -1,7 +1,6 @@ import 'dart:io' show File; import 'package:PiliPlus/common/constants.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/constants.dart'; @@ -129,7 +128,7 @@ class _EditProfilePageState extends State { return switch (loadingState) { Loading() => m3eLoading, - Success(:final response) => listView( + Success(:final response) => ListView( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 25, ), diff --git a/lib/pages/member_search/child/view.dart b/lib/pages/member_search/child/view.dart index 375ae6c98..1a4cf5bf6 100644 --- a/lib/pages/member_search/child/view.dart +++ b/lib/pages/member_search/child/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_h.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -37,7 +36,7 @@ class _MemberSearchChildPageState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/member_season_series/view.dart b/lib/pages/member_season_series/view.dart index a2fa693b3..9e3439fae 100644 --- a/lib/pages/member_season_series/view.dart +++ b/lib/pages/member_season_series/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -45,7 +44,7 @@ class _SeasonSeriesPageState extends State @override Widget build(BuildContext context) { super.build(context); - return customScrollView( + return CustomScrollView( slivers: [ SliverPadding( padding: EdgeInsets.only( diff --git a/lib/pages/member_shop/view.dart b/lib/pages/member_shop/view.dart index 74a06950e..8d8120f93 100644 --- a/lib/pages/member_shop/view.dart +++ b/lib/pages/member_shop/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/space_opus.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space/space_shop/item.dart'; @@ -46,7 +45,7 @@ class _MemberShopState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/member_upower_rank/view.dart b/lib/pages/member_upower_rank/view.dart index 09c744c4a..a10f2e2fd 100644 --- a/lib/pages/member_upower_rank/view.dart +++ b/lib/pages/member_upower_rank/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -73,7 +72,7 @@ class _UpowerRankPageState extends State final padding = MediaQuery.viewPaddingOf(context); final child = refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/member_video/view.dart b/lib/pages/member_video/view.dart index b7f87d68a..1ec37c9d5 100644 --- a/lib/pages/member_video/view.dart +++ b/lib/pages/member_video/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; @@ -100,7 +99,7 @@ class _MemberVideoState extends State } } }, - child: customScrollView( + child: CustomScrollView( physics: ReloadScrollPhysics(controller: _controller), slivers: [ SliverPadding( diff --git a/lib/pages/member_video_web/base/view.dart b/lib/pages/member_video_web/base/view.dart index ebd1fd197..a476c194e 100644 --- a/lib/pages/member_video_web/base/view.dart +++ b/lib/pages/member_video_web/base/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_header.dart'; @@ -64,7 +63,7 @@ abstract class BaseVideoWebState< ), body: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: ReloadScrollPhysics(controller: controller), slivers: [ SliverPadding( diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 81fac2845..e133eb72a 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -4,7 +4,6 @@ import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/nav_bar_config.dart'; @@ -79,7 +78,7 @@ class _MediaPageState extends CommonPageState child: refreshIndicator( onRefresh: controller.onRefresh, child: onBuild( - listView( + ListView( padding: const .only(bottom: 100), physics: const AlwaysScrollableScrollPhysics(), children: [ diff --git a/lib/pages/msg_feed_top/at_me/view.dart b/lib/pages/msg_feed_top/at_me/view.dart index 7f2d3701a..554888ee6 100644 --- a/lib/pages/msg_feed_top/at_me/view.dart +++ b/lib/pages/msg_feed_top/at_me/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pbenum.dart' @@ -53,7 +52,7 @@ class _AtMePageState extends State { ), body: refreshIndicator( onRefresh: _atMeController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/msg_feed_top/like_detail/view.dart b/lib/pages/msg_feed_top/like_detail/view.dart index 20e24c89e..c4f55fc2a 100644 --- a/lib/pages/msg_feed_top/like_detail/view.dart +++ b/lib/pages/msg_feed_top/like_detail/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -35,7 +34,7 @@ class _LikeDetailPageState extends State { appBar: AppBar(title: const Text('点赞详情')), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/msg_feed_top/like_me/view.dart b/lib/pages/msg_feed_top/like_me/view.dart index b20bd2d33..c5164002c 100644 --- a/lib/pages/msg_feed_top/like_me/view.dart +++ b/lib/pages/msg_feed_top/like_me/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; @@ -54,7 +53,7 @@ class _LikeMePageState extends State { ), body: refreshIndicator( onRefresh: _likeMeController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/msg_feed_top/reply_me/view.dart b/lib/pages/msg_feed_top/reply_me/view.dart index 63a2781cb..ed941d6db 100644 --- a/lib/pages/msg_feed_top/reply_me/view.dart +++ b/lib/pages/msg_feed_top/reply_me/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/msg_feed_top.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pbenum.dart' @@ -53,7 +52,7 @@ class _ReplyMePageState extends State { ), body: refreshIndicator( onRefresh: _replyMeController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/msg_feed_top/sys_msg/view.dart b/lib/pages/msg_feed_top/sys_msg/view.dart index cee244a10..e33e34a42 100644 --- a/lib/pages/msg_feed_top/sys_msg/view.dart +++ b/lib/pages/msg_feed_top/sys_msg/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/msg_feed_sys_msg_.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -38,7 +37,7 @@ class _SysMsgPageState extends State { appBar: AppBar(title: const Text('系统通知')), body: refreshIndicator( onRefresh: _sysMsgController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/music/video/view.dart b/lib/pages/music/video/view.dart index dff82ca41..2d6bad63a 100644 --- a/lib/pages/music/video/view.dart +++ b/lib/pages/music/video/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -34,7 +33,7 @@ class _MusicRecommendPageState extends State color: theme.colorScheme.surface, child: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ _buildAppBar(theme, padding), diff --git a/lib/pages/music/view.dart b/lib/pages/music/view.dart index 2fd35d84c..e637c6bfe 100644 --- a/lib/pages/music/view.dart +++ b/lib/pages/music/view.dart @@ -4,7 +4,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/image_viewer/hero.dart'; import 'package:PiliPlus/common/widgets/marquee.dart'; @@ -115,7 +114,7 @@ class _MusicDetailPageState extends CommonDynPageState { if (isPortrait) { child = Padding( padding: EdgeInsets.symmetric(horizontal: padding), - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -141,7 +140,7 @@ class _MusicDetailPageState extends CommonDynPageState { children: [ Expanded( flex: flex, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ @@ -174,7 +173,7 @@ class _MusicDetailPageState extends CommonDynPageState { resizeToAvoidBottomInset: false, body: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/my_reply/view.dart b/lib/pages/my_reply/view.dart index 4c789e6dc..a10553dc7 100644 --- a/lib/pages/my_reply/view.dart +++ b/lib/pages/my_reply/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/dialog/export_import.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' @@ -77,7 +76,7 @@ class _MyReplyState extends State with DynMixin { const SizedBox(width: 6), ], ), - body: customScrollView( + body: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ _replies.isNotEmpty diff --git a/lib/pages/pgc/view.dart b/lib/pages/pgc/view.dart index dba8806cc..d56e5fc4f 100644 --- a/lib/pages/pgc/view.dart +++ b/lib/pages/pgc/view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/button/more_btn.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; @@ -58,7 +57,7 @@ class _PgcPageState extends State with AutomaticKeepAliveClientMixin { final ThemeData theme = Theme.of(context); return refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/pgc_index/view.dart b/lib/pages/pgc_index/view.dart index 69b02f1c3..4da07b810 100644 --- a/lib/pages/pgc_index/view.dart +++ b/lib/pages/pgc_index/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/style.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/common/widgets/self_sized_horizontal_list.dart'; @@ -68,7 +67,7 @@ class _PgcIndexPageState extends State if (count == 0) return const SizedBox.shrink(); return Padding( padding: EdgeInsets.only(left: padding.left, right: padding.right), - child: customScrollView( + child: CustomScrollView( controller: _ctr.scrollController, slivers: [ if (widget.indexType != null) diff --git a/lib/pages/pgc_review/child/view.dart b/lib/pages/pgc_review/child/view.dart index 405ef561e..7660e3c61 100644 --- a/lib/pages/pgc_review/child/view.dart +++ b/lib/pages/pgc_review/child/view.dart @@ -3,7 +3,6 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/flutter/selectable_text/selectable_text.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; @@ -68,7 +67,7 @@ class _PgcReviewChildPageState extends State final theme = Theme.of(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/popular_precious/view.dart b/lib/pages/popular_precious/view.dart index 6fa32d903..aee184759 100644 --- a/lib/pages/popular_precious/view.dart +++ b/lib/pages/popular_precious/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_h.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; @@ -30,7 +29,7 @@ class _PopularPreciousPageState extends State appBar: AppBar(title: const Text('入站必刷')), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ ViewSliverSafeArea( diff --git a/lib/pages/popular_series/view.dart b/lib/pages/popular_series/view.dart index c4e34e7c0..a36b5a13a 100644 --- a/lib/pages/popular_series/view.dart +++ b/lib/pages/popular_series/view.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; @@ -42,7 +41,7 @@ class _PopularSeriesPageState extends State with GridMixin { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: ReloadScrollPhysics(controller: _controller), slivers: [ ViewSliverSafeArea( diff --git a/lib/pages/rank/zone/view.dart b/lib/pages/rank/zone/view.dart index 9b59d4094..f5ae671ff 100644 --- a/lib/pages/rank/zone/view.dart +++ b/lib/pages/rank/zone/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_h.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -41,7 +40,7 @@ class _ZonePageState extends State super.build(context); return refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/rcmd/view.dart b/lib/pages/rcmd/view.dart index 74321a7de..cae5cd4b1 100644 --- a/lib/pages/rcmd/view.dart +++ b/lib/pages/rcmd/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_v.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/video_card/video_card_v.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -35,7 +34,7 @@ class _RcmdPageState extends State decoration: const BoxDecoration(borderRadius: Style.mdRadius), child: refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/search/view.dart b/lib/pages/search/view.dart index b98022140..7f7500dee 100644 --- a/lib/pages/search/view.dart +++ b/lib/pages/search/view.dart @@ -2,7 +2,6 @@ import 'dart:convert'; import 'package:PiliPlus/common/widgets/dialog/export_import.dart'; import 'package:PiliPlus/common/widgets/disabled_icon.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/sliver_wrap.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -62,7 +61,7 @@ class _SearchPageState extends State { appBar: _buildAppBar, body: Padding( padding: .only(left: padding.left, right: padding.right), - child: customScrollView( + child: CustomScrollView( slivers: [ if (_searchController.searchSuggestion) _buildSearchSuggest(), if (isPortrait) ...[ diff --git a/lib/pages/search_panel/view.dart b/lib/pages/search_panel/view.dart index 8360024c9..707294efe 100644 --- a/lib/pages/search_panel/view.dart +++ b/lib/pages/search_panel/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models/common/search/search_type.dart'; @@ -45,7 +44,7 @@ abstract class CommonSearchPanelState< final theme = Theme.of(context); return refreshIndicator( onRefresh: controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/search_trending/view.dart b/lib/pages/search_trending/view.dart index 2b3f31328..d55756671 100644 --- a/lib/pages/search_trending/view.dart +++ b/lib/pages/search_trending/view.dart @@ -3,7 +3,6 @@ import 'dart:math'; import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -119,7 +118,7 @@ class _SearchTrendingPageState extends State { width: width, child: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/setting/extra_setting.dart b/lib/pages/setting/extra_setting.dart index 91701f5ad..0c6343e0c 100644 --- a/lib/pages/setting/extra_setting.dart +++ b/lib/pages/setting/extra_setting.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/setting/models/extra_settings.dart'; import 'package:flutter/material.dart'; @@ -21,7 +20,7 @@ class _ExtraSettingState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: showAppBar ? AppBar(title: const Text('其它设置')) : null, - body: ExtendedListView.builder( + body: ListView.builder( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/setting/pages/color_select.dart b/lib/pages/setting/pages/color_select.dart index cbfbd49eb..3bb7476bf 100644 --- a/lib/pages/setting/pages/color_select.dart +++ b/lib/pages/setting/pages/color_select.dart @@ -1,7 +1,6 @@ import 'dart:io' show Platform; import 'package:PiliPlus/common/widgets/color_palette.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/main.dart' show MyApp; import 'package:PiliPlus/models/common/nav_bar_config.dart'; import 'package:PiliPlus/models/common/theme/theme_color_type.dart'; @@ -68,7 +67,7 @@ class _ColorSelectPageState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar(title: const Text('选择应用主题')), - body: listView( + body: ListView( children: [ ListTile( onTap: () async { diff --git a/lib/pages/setting/pages/logs.dart b/lib/pages/setting/pages/logs.dart index 703a9fc0d..040b26621 100644 --- a/lib/pages/setting/pages/logs.dart +++ b/lib/pages/setting/pages/logs.dart @@ -3,7 +3,6 @@ import 'dart:convert'; import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/services/logger.dart'; import 'package:PiliPlus/utils/date_utils.dart'; @@ -164,7 +163,7 @@ class _LogsPageState extends State { left: padding.left + 12, right: padding.right + 12, ), - child: customScrollView( + child: CustomScrollView( slivers: [ if (latestLog != null) SliverToBoxAdapter( diff --git a/lib/pages/setting/pages/play_speed_set.dart b/lib/pages/setting/pages/play_speed_set.dart index 602b3ebcb..aa67061b3 100644 --- a/lib/pages/setting/pages/play_speed_set.dart +++ b/lib/pages/setting/pages/play_speed_set.dart @@ -1,7 +1,6 @@ import 'dart:math'; import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/pages/setting/widgets/switch_item.dart'; import 'package:PiliPlus/utils/extension/context_ext.dart'; @@ -201,7 +200,7 @@ class _PlaySpeedPageState extends State { ], ), body: ViewSafeArea( - child: listView( + child: ListView( children: [ Padding( padding: const EdgeInsets.only( diff --git a/lib/pages/setting/play_setting.dart b/lib/pages/setting/play_setting.dart index 4d2273180..6c97855a5 100644 --- a/lib/pages/setting/play_setting.dart +++ b/lib/pages/setting/play_setting.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/setting/models/play_settings.dart'; import 'package:flutter/material.dart'; @@ -21,7 +20,7 @@ class _PlaySettingState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: showAppBar ? AppBar(title: const Text('播放器设置')) : null, - body: ExtendedListView.builder( + body: ListView.builder( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/setting/recommend_setting.dart b/lib/pages/setting/recommend_setting.dart index 01ae3100d..d77315fe3 100644 --- a/lib/pages/setting/recommend_setting.dart +++ b/lib/pages/setting/recommend_setting.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/setting/models/recommend_settings.dart'; import 'package:flutter/material.dart' hide ListTile; @@ -23,7 +22,7 @@ class _RecommendSettingState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: widget.showAppBar ? AppBar(title: const Text('推荐流设置')) : null, - body: listView( + body: ListView( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/setting/style_setting.dart b/lib/pages/setting/style_setting.dart index b53619458..1b13350d7 100644 --- a/lib/pages/setting/style_setting.dart +++ b/lib/pages/setting/style_setting.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/setting/models/style_settings.dart'; import 'package:flutter/material.dart'; @@ -21,7 +20,7 @@ class _StyleSettingState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: showAppBar ? AppBar(title: const Text('外观设置')) : null, - body: ExtendedListView.builder( + body: ListView.builder( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/setting/video_setting.dart b/lib/pages/setting/video_setting.dart index ba32d3c85..495720aa6 100644 --- a/lib/pages/setting/video_setting.dart +++ b/lib/pages/setting/video_setting.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/setting/models/video_settings.dart'; import 'package:flutter/material.dart'; @@ -21,7 +20,7 @@ class _VideoSettingState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: showAppBar ? AppBar(title: const Text('音视频设置')) : null, - body: ExtendedListView.builder( + body: ListView.builder( padding: EdgeInsets.only( left: showAppBar ? padding.left : 0, right: showAppBar ? padding.right : 0, diff --git a/lib/pages/setting/view.dart b/lib/pages/setting/view.dart index 4fb8c7eda..fb94fa9c5 100644 --- a/lib/pages/setting/view.dart +++ b/lib/pages/setting/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/list_tile.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/http/login.dart'; import 'package:PiliPlus/models/common/setting_type.dart'; @@ -171,7 +170,7 @@ class _SettingPageState extends State { TextStyle subTitleStyle = theme.textTheme.labelMedium!.copyWith( color: theme.colorScheme.outline, ); - return listView( + return ListView( padding: EdgeInsets.only(bottom: padding.bottom + 100), children: [ _buildSearchItem(theme), diff --git a/lib/pages/settings_search/view.dart b/lib/pages/settings_search/view.dart index bb88ccb70..ba69b26b5 100644 --- a/lib/pages/settings_search/view.dart +++ b/lib/pages/settings_search/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/pages/search/controller.dart' show DebounceStreamState; @@ -89,7 +88,7 @@ class _SettingsSearchPageState ), ), ), - body: customScrollView( + body: CustomScrollView( slivers: [ ViewSliverSafeArea( sliver: Obx( diff --git a/lib/pages/space_setting/view.dart b/lib/pages/space_setting/view.dart index f314c124f..4cfb6555d 100644 --- a/lib/pages/space_setting/view.dart +++ b/lib/pages/space_setting/view.dart @@ -1,6 +1,5 @@ import 'dart:math'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/space_setting/privacy.dart'; @@ -55,7 +54,7 @@ class _SpaceSettingPageState extends State { color: theme.colorScheme.outline.withValues(alpha: 0.1), ), ); - return customScrollView( + return CustomScrollView( slivers: [ dividerL, SliverList.separated( diff --git a/lib/pages/sponsor_block/view.dart b/lib/pages/sponsor_block/view.dart index b0dfa8624..b372b532b 100644 --- a/lib/pages/sponsor_block/view.dart +++ b/lib/pages/sponsor_block/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/http/constants.dart'; import 'package:PiliPlus/http/init.dart'; @@ -486,7 +485,7 @@ class _SponsorBlockPageState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar(title: const Text('空降助手')), - body: customScrollView( + body: CustomScrollView( slivers: [ dividerL, SliverToBoxAdapter(child: _serverStatusItem(theme, titleStyle)), diff --git a/lib/pages/subscription/view.dart b/lib/pages/subscription/view.dart index b00e5fe2a..6d9ef4d63 100644 --- a/lib/pages/subscription/view.dart +++ b/lib/pages/subscription/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/view_sliver_safe_area.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -27,7 +26,7 @@ class _SubPageState extends State with GridMixin { appBar: AppBar(title: const Text('我的订阅')), body: refreshIndicator( onRefresh: _subController.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ ViewSliverSafeArea( diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index 14ef0d7b0..2e76c4df0 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -55,7 +54,7 @@ class _SubDetailPageState extends State with GridMixin { color: theme.colorScheme.surface, child: refreshIndicator( onRefresh: _subDetailController.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _subDetailController.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/video/ai_conclusion/view.dart b/lib/pages/video/ai_conclusion/view.dart index 5ee5801ec..f3ae11c13 100644 --- a/lib/pages/video/ai_conclusion/view.dart +++ b/lib/pages/video/ai_conclusion/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/flutter/selectable_text/text.dart'; import 'package:PiliPlus/common/widgets/gesture/tap_gesture_recognizer.dart'; import 'package:PiliPlus/models_new/video/video_ai_conclusion/model_result.dart'; @@ -27,7 +26,7 @@ class AiConclusionPanel extends CommonSlidePage { Key? key, bool tap = true, }) { - return customScrollView( + return CustomScrollView( key: key, shrinkWrap: !tap, physics: const AlwaysScrollableScrollPhysics(), diff --git a/lib/pages/video/download_panel/view.dart b/lib/pages/video/download_panel/view.dart index e9a73aa46..9f14590b5 100644 --- a/lib/pages/video/download_panel/view.dart +++ b/lib/pages/video/download_panel/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; @@ -176,7 +175,7 @@ class _DownloadPanelState extends State { return Expanded( child: Material( type: MaterialType.transparency, - child: customScrollView( + child: CustomScrollView( controller: widget.scrollController, slivers: [ SliverPadding( diff --git a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart index 11093803d..c8619e1e2 100644 --- a/lib/pages/video/introduction/pgc/widgets/intro_detail.dart +++ b/lib/pages/video/introduction/pgc/widgets/intro_detail.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/page/tabs.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/flutter/selectable_text/text.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/scroll_physics.dart'; @@ -118,7 +117,7 @@ class _IntroDetailState extends State final TextStyle textStyle = TextStyle( color: theme.colorScheme.onSurfaceVariant, ); - return listView( + return ListView( controller: _controller, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only( diff --git a/lib/pages/video/medialist/view.dart b/lib/pages/video/medialist/view.dart index cc16b99c8..d322d7316 100644 --- a/lib/pages/video/medialist/view.dart +++ b/lib/pages/video/medialist/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; import 'package:PiliPlus/common/widgets/dialog/dialog.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/stat/stat.dart'; @@ -121,7 +120,7 @@ class _MediaListPanelState extends State Widget _buildList(ThemeData theme) { final showDelBtn = widget.onDelete != null && widget.mediaList.length > 1; - return customScrollView( + return CustomScrollView( controller: _controller, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index 3d9cc9c53..8816a62e3 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_card_h.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; @@ -90,7 +89,7 @@ class _HorizontalMemberPageState extends State { Expanded( child: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/video/note/view.dart b/lib/pages/video/note/view.dart index 7f2fd231c..f8ac82f27 100644 --- a/lib/pages/video/note/view.dart +++ b/lib/pages/video/note/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -110,7 +109,7 @@ class _NoteListPageState extends State Widget buildList(ThemeData theme) { Widget child = refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( key: _key, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/video/post_panel/view.dart b/lib/pages/video/post_panel/view.dart index 94b1bae34..b2b6c6153 100644 --- a/lib/pages/video/post_panel/view.dart +++ b/lib/pages/video/post_panel/view.dart @@ -2,7 +2,6 @@ import 'dart:async'; import 'dart:math'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/pair.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -253,7 +252,7 @@ class _PostPanelState extends State return const HttpError(isSliver: false); } final bottom = MediaQuery.viewPaddingOf(context).bottom; - Widget child = ExtendedListView.builder( + Widget child = ListView.builder( key: _key, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only(bottom: 88 + bottom), diff --git a/lib/pages/video/reply/view.dart b/lib/pages/video/reply/view.dart index 6d180cd97..ad86d5cd2 100644 --- a/lib/pages/video/reply/view.dart +++ b/lib/pages/video/reply/view.dart @@ -1,7 +1,6 @@ import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_floating_header.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' @@ -83,7 +82,7 @@ class _VideoReplyPanelState extends State child: Stack( clipBehavior: Clip.none, children: [ - customScrollView( + CustomScrollView( controller: widget.isNested ? null : _videoReplyController.scrollController, diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index 8024e6d3b..efa174847 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/skeleton/video_reply.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/colored_box_transition.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/sliver/sliver_pinned_header.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; @@ -187,7 +186,7 @@ class _VideoReplyReplyPanelState extends State final child = refreshIndicator( onRefresh: _controller.onRefresh, isClampingScrollPhysics: widget.isNested, - child: customScrollView( + child: CustomScrollView( key: ValueKey(scrollController.hashCode), controller: scrollController, physics: const AlwaysScrollableScrollPhysics(), diff --git a/lib/pages/video/reply_search_item/child/view.dart b/lib/pages/video/reply_search_item/child/view.dart index 89db44907..d73cecedc 100644 --- a/lib/pages/video/reply_search_item/child/view.dart +++ b/lib/pages/video/reply_search_item/child/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show SearchItem; @@ -34,7 +33,7 @@ class _ReplySearchChildPageState extends State super.build(context); return refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( controller: _controller.scrollController, physics: const AlwaysScrollableScrollPhysics(), slivers: [ diff --git a/lib/pages/video/send_danmaku/view.dart b/lib/pages/video/send_danmaku/view.dart index fcc8dfe46..68018e228 100644 --- a/lib/pages/video/send_danmaku/view.dart +++ b/lib/pages/video/send_danmaku/view.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/view_safe_area.dart'; import 'package:PiliPlus/http/danmaku.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -180,7 +179,7 @@ class _SendDanmakuPanelState extends CommonTextPubPageState { ), ), ), - child: listView( + child: ListView( physics: const ClampingScrollPhysics(), padding: .only( top: 12, diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index 540d24c3a..a39eb0869 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -7,7 +7,6 @@ import 'package:PiliPlus/common/assets.dart'; import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/custom_icon.dart'; import 'package:PiliPlus/common/widgets/flutter/pop_scope.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/keep_alive_wrapper.dart'; import 'package:PiliPlus/common/widgets/route_aware_mixin.dart'; @@ -1030,7 +1029,7 @@ class _VideoDetailPageVState extends State localIntroPanel() else if (showIntro) KeepAliveWrapper( - child: customScrollView( + child: CustomScrollView( key: const PageStorageKey(CommonIntroController), controller: videoDetailController.effectiveIntroScrollCtr, @@ -1689,7 +1688,7 @@ class _VideoDetailPageVState extends State Widget localIntroPanel({ bool needCtr = true, }) { - return customScrollView( + return CustomScrollView( controller: needCtr ? videoDetailController.effectiveIntroScrollCtr : null, @@ -1721,7 +1720,7 @@ class _VideoDetailPageVState extends State return localIntroPanel(needCtr: needCtr); } Widget introPanel() { - Widget child = customScrollView( + Widget child = CustomScrollView( key: const PageStorageKey(CommonIntroController), controller: needCtr ? videoDetailController.effectiveIntroScrollCtr diff --git a/lib/pages/video/view_point/view.dart b/lib/pages/video/view_point/view.dart index 2049e6ee2..26d54a555 100644 --- a/lib/pages/video/view_point/view.dart +++ b/lib/pages/video/view_point/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/style.dart'; import 'package:PiliPlus/common/widgets/button/icon_button.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/progress_bar/segment_progress_bar.dart'; import 'package:PiliPlus/pages/common/slide/common_slide_page.dart'; @@ -92,7 +91,7 @@ class _ViewPointsPageState extends State @override Widget buildList(ThemeData theme) { - final child = ExtendedListView.builder( + final child = ListView.builder( key: _key, physics: const AlwaysScrollableScrollPhysics(), padding: EdgeInsets.only( diff --git a/lib/pages/webdav/view.dart b/lib/pages/webdav/view.dart index 49ecfa029..f71cf6c37 100644 --- a/lib/pages/webdav/view.dart +++ b/lib/pages/webdav/view.dart @@ -1,5 +1,4 @@ import 'package:PiliPlus/common/style.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/pages/webdav/webdav.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/storage_key.dart'; @@ -44,7 +43,7 @@ class _WebDavSettingPageState extends State { body: Stack( clipBehavior: Clip.none, children: [ - listView( + ListView( padding: padding.copyWith( top: 20, left: 20 + (showAppBar ? padding.left : 0), diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index 3694827aa..04e8fa987 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/whisper_item.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -95,7 +94,7 @@ class _WhisperPageState extends State { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ _buildTopItems(theme, padding), diff --git a/lib/pages/whisper_link_setting/view.dart b/lib/pages/whisper_link_setting/view.dart index 876501de5..a85f2a550 100644 --- a/lib/pages/whisper_link_setting/view.dart +++ b/lib/pages/whisper_link_setting/view.dart @@ -1,4 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/pendant_avatar.dart'; import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/models_new/msg/im_user_infos/datum.dart'; @@ -50,7 +49,7 @@ class _WhisperLinkSettingPageState extends State { return Scaffold( resizeToAvoidBottomInset: false, appBar: AppBar(title: const Text('聊天设置')), - body: listView( + body: ListView( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 100, ), diff --git a/lib/pages/whisper_secondary/view.dart b/lib/pages/whisper_secondary/view.dart index d4e7fb342..cabab1358 100644 --- a/lib/pages/whisper_secondary/view.dart +++ b/lib/pages/whisper_secondary/view.dart @@ -1,6 +1,5 @@ import 'package:PiliPlus/common/skeleton/whisper_item.dart'; import 'package:PiliPlus/common/widgets/flutter/refresh_indicator.dart'; -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart'; import 'package:PiliPlus/http/loading_state.dart'; @@ -74,7 +73,7 @@ class _WhisperSecPageState extends State { ), body: refreshIndicator( onRefresh: _controller.onRefresh, - child: customScrollView( + child: CustomScrollView( physics: const AlwaysScrollableScrollPhysics(), slivers: [ SliverPadding( diff --git a/lib/pages/whisper_settings/view.dart b/lib/pages/whisper_settings/view.dart index f6629387a..070a983f6 100644 --- a/lib/pages/whisper_settings/view.dart +++ b/lib/pages/whisper_settings/view.dart @@ -1,5 +1,3 @@ -import 'package:PiliPlus/common/widgets/flutter/scroll_view/scroll_view.dart' - show ExtendedListView; import 'package:PiliPlus/common/widgets/loading_widget/loading_widget.dart'; import 'package:PiliPlus/grpc/bilibili/app/im/v1.pb.dart' show IMSettingType, Setting; @@ -167,7 +165,7 @@ class _WhisperSettingsPageState extends State { Success>(:final response) => Builder( builder: (context) { final keys = response.keys.toList()..sort(); - return ExtendedListView.separated( + return ListView.separated( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context).bottom + 100, ),