Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-05-01 10:37:31 +08:00
parent 91a14d8286
commit d27f5f315c
71 changed files with 94 additions and 1561 deletions

View File

@@ -1,13 +1,10 @@
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:flutter/material.dart';
class CustomToast extends StatelessWidget {
const CustomToast({super.key, required this.msg});
const CustomToast(this.msg, {super.key});
final String msg;
static double toastOpacity = Pref.defaultToastOp;
@override
Widget build(BuildContext context) {
final colorScheme = ColorScheme.of(context);
@@ -17,7 +14,7 @@ class CustomToast extends StatelessWidget {
),
padding: const EdgeInsets.symmetric(horizontal: 17, vertical: 10),
decoration: BoxDecoration(
color: colorScheme.primaryContainer.withValues(alpha: toastOpacity),
color: colorScheme.primaryContainer,
borderRadius: const BorderRadius.all(Radius.circular(20)),
),
child: Text(
@@ -32,7 +29,7 @@ class CustomToast extends StatelessWidget {
}
class LoadingWidget extends StatelessWidget {
const LoadingWidget({super.key, required this.msg});
const LoadingWidget(this.msg, {super.key});
///loading msg
final String msg;

View File

@@ -22,7 +22,7 @@ import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/rendering/sliver_
import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/sliver_persistent_header.dart';
import 'package:PiliPlus/common/widgets/only_layout_widget.dart'
show LayoutCallback;
import 'package:flutter/foundation.dart';
import 'package:flutter/foundation.dart' show describeIdentity, clampDouble;
import 'package:flutter/material.dart'
hide SliverPersistentHeader, SliverPersistentHeaderDelegate;
import 'package:flutter/rendering.dart' show RenderOpacity, OpacityLayer;

View File

@@ -19,7 +19,7 @@ import 'dart:math' as math;
import 'package:PiliPlus/common/widgets/dynamic_sliver_app_bar/sliver_persistent_header.dart';
import 'package:PiliPlus/common/widgets/only_layout_widget.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/foundation.dart' show clampDouble;
import 'package:flutter/rendering.dart' hide LayoutCallback;
import 'package:flutter/widgets.dart'
hide SliverPersistentHeader, SliverPersistentHeaderDelegate;

View File

@@ -1,370 +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:ui' show SemanticsRole;
import 'package:flutter/foundation.dart' show clampDouble;
import 'package:flutter/gestures.dart' show DragStartBehavior;
import 'package:flutter/material.dart' hide TabBarView;
/// A page view that displays the widget which corresponds to the currently
/// selected tab.
///
/// This widget is typically used in conjunction with a [TabBar].
///
/// {@youtube 560 315 https://www.youtube.com/watch?v=POtoEH-5l40}
///
/// If a [TabController] is not provided, then there must be a [DefaultTabController]
/// ancestor.
///
/// The tab controller's [TabController.length] must equal the length of the
/// [children] list and the length of the [TabBar.tabs] list.
///
/// To see a sample implementation, visit the [TabController] documentation.
class CustomTabBarView extends StatefulWidget {
/// Creates a page view with one child per tab.
///
/// The length of [children] must be the same as the [controller]'s length.
const CustomTabBarView({
super.key,
required this.children,
this.controller,
this.physics,
this.dragStartBehavior = DragStartBehavior.start,
this.viewportFraction = 1.0,
this.clipBehavior = Clip.hardEdge,
this.scrollDirection = Axis.horizontal,
});
/// This widget's selection and animation state.
///
/// If [TabController] is not provided, then the value of [DefaultTabController.of]
/// will be used.
final TabController? controller;
/// One widget per tab.
///
/// Its length must match the length of the [TabBar.tabs]
/// list, as well as the [controller]'s [TabController.length].
final List<Widget> children;
/// How the page view should respond to user input.
///
/// For example, determines how the page view continues to animate after the
/// user stops dragging the page view.
///
/// The physics are modified to snap to page boundaries using
/// [PageScrollPhysics] prior to being used.
///
/// Defaults to matching platform conventions.
final ScrollPhysics? physics;
/// {@macro flutter.widgets.scrollable.dragStartBehavior}
final DragStartBehavior dragStartBehavior;
/// {@macro flutter.widgets.pageview.viewportFraction}
final double viewportFraction;
/// {@macro flutter.material.Material.clipBehavior}
///
/// Defaults to [Clip.hardEdge].
final Clip clipBehavior;
final Axis scrollDirection;
@override
State<CustomTabBarView> createState() => _CustomTabBarViewState();
}
class _CustomTabBarViewState extends State<CustomTabBarView> {
TabController? _controller;
PageController? _pageController;
late List<Widget> _childrenWithKey;
int? _currentIndex;
int _warpUnderwayCount = 0;
int _scrollUnderwayCount = 0;
bool _debugHasScheduledValidChildrenCountCheck = false;
// If the TabBarView is rebuilt with a new tab controller, the caller should
// dispose the old one. In that case the old controller's animation will be
// null and should not be accessed.
bool get _controllerIsValid => _controller?.animation != null;
void _updateTabController() {
final TabController? newController =
widget.controller ?? DefaultTabController.maybeOf(context);
assert(() {
if (newController == null) {
throw FlutterError(
'No TabController for ${widget.runtimeType}.\n'
'When creating a ${widget.runtimeType}, you must either provide an explicit '
'TabController using the "controller" property, or you must ensure that there '
'is a DefaultTabController above the ${widget.runtimeType}.\n'
'In this case, there was neither an explicit controller nor a default controller.',
);
}
return true;
}());
if (newController == _controller) {
return;
}
if (_controllerIsValid) {
_controller!.animation!.removeListener(_handleTabControllerAnimationTick);
}
_controller = newController;
if (_controller != null) {
_controller!.animation!.addListener(_handleTabControllerAnimationTick);
}
}
void _jumpToPage(int page) {
_warpUnderwayCount += 1;
_pageController!.jumpToPage(page);
_warpUnderwayCount -= 1;
}
Future<void> _animateToPage(
int page, {
required Duration duration,
required Curve curve,
}) async {
_warpUnderwayCount += 1;
await _pageController!.animateToPage(
page,
duration: duration,
curve: curve,
);
_warpUnderwayCount -= 1;
}
@override
void initState() {
super.initState();
_updateChildren();
}
@override
void didChangeDependencies() {
super.didChangeDependencies();
_updateTabController();
_currentIndex = _controller!.index;
if (_pageController == null) {
_pageController = PageController(
initialPage: _currentIndex!,
viewportFraction: widget.viewportFraction,
);
} else {
_pageController!.jumpToPage(_currentIndex!);
}
}
@override
void didUpdateWidget(CustomTabBarView oldWidget) {
super.didUpdateWidget(oldWidget);
if (widget.controller != oldWidget.controller) {
_updateTabController();
_currentIndex = _controller!.index;
_jumpToPage(_currentIndex!);
}
if (widget.viewportFraction != oldWidget.viewportFraction) {
_pageController?.dispose();
_pageController = PageController(
initialPage: _currentIndex!,
viewportFraction: widget.viewportFraction,
);
}
// While a warp is under way, we stop updating the tab page contents.
// This is tracked in https://github.com/flutter/flutter/issues/31269.
if (widget.children != oldWidget.children && _warpUnderwayCount == 0) {
_updateChildren();
}
}
@override
void dispose() {
if (_controllerIsValid) {
_controller!.animation!.removeListener(_handleTabControllerAnimationTick);
}
_controller = null;
_pageController?.dispose();
// We don't own the _controller Animation, so it's not disposed here.
super.dispose();
}
void _updateChildren() {
_childrenWithKey = KeyedSubtree.ensureUniqueKeysForList(
widget.children.map<Widget>((Widget child) {
return Semantics(role: SemanticsRole.tabPanel, child: child);
}).toList(),
);
}
void _handleTabControllerAnimationTick() {
if (_scrollUnderwayCount > 0 || !_controller!.indexIsChanging) {
return;
} // This widget is driving the controller's animation.
if (_controller!.index != _currentIndex) {
_currentIndex = _controller!.index;
_warpToCurrentIndex();
}
}
void _warpToCurrentIndex() {
if (!mounted || _pageController!.page == _currentIndex!.toDouble()) {
return;
}
final bool adjacentDestination =
(_currentIndex! - _controller!.previousIndex).abs() == 1;
if (adjacentDestination) {
_warpToAdjacentTab(_controller!.animationDuration);
} else {
_warpToNonAdjacentTab(_controller!.animationDuration);
}
}
Future<void> _warpToAdjacentTab(Duration duration) async {
if (duration == Duration.zero) {
_jumpToPage(_currentIndex!);
} else {
await _animateToPage(
_currentIndex!,
duration: duration,
curve: Curves.ease,
);
}
if (mounted) {
setState(_updateChildren);
}
return Future<void>.value();
}
Future<void> _warpToNonAdjacentTab(Duration duration) async {
final int previousIndex = _controller!.previousIndex;
assert((_currentIndex! - previousIndex).abs() > 1);
// initialPage defines which page is shown when starting the animation.
// This page is adjacent to the destination page.
final int initialPage = _currentIndex! > previousIndex
? _currentIndex! - 1
: _currentIndex! + 1;
setState(() {
// Needed for `RenderSliverMultiBoxAdaptor.move` and kept alive children.
// For motivation, see https://github.com/flutter/flutter/pull/29188 and
// https://github.com/flutter/flutter/issues/27010#issuecomment-486475152.
_childrenWithKey = List<Widget>.of(_childrenWithKey, growable: false);
final Widget temp = _childrenWithKey[initialPage];
_childrenWithKey[initialPage] = _childrenWithKey[previousIndex];
_childrenWithKey[previousIndex] = temp;
});
// Make a first jump to the adjacent page.
_jumpToPage(initialPage);
// Jump or animate to the destination page.
if (duration == Duration.zero) {
_jumpToPage(_currentIndex!);
} else {
await _animateToPage(
_currentIndex!,
duration: duration,
curve: Curves.ease,
);
}
if (mounted) {
setState(_updateChildren);
}
}
void _syncControllerOffset() {
_controller!.offset = clampDouble(
_pageController!.page! - _controller!.index,
-1.0,
1.0,
);
}
// Called when the PageView scrolls
bool _handleScrollNotification(ScrollNotification notification) {
if (_warpUnderwayCount > 0 || _scrollUnderwayCount > 0) {
return false;
}
if (notification.depth != 0) {
return false;
}
if (!_controllerIsValid) {
return false;
}
_scrollUnderwayCount += 1;
final double page = _pageController!.page!;
if (notification is ScrollUpdateNotification &&
!_controller!.indexIsChanging) {
final bool pageChanged = (page - _controller!.index).abs() > 1.0;
if (pageChanged) {
_controller!.index = page.round();
_currentIndex = _controller!.index;
}
_syncControllerOffset();
} else if (notification is ScrollEndNotification) {
_controller!.index = page.round();
_currentIndex = _controller!.index;
if (!_controller!.indexIsChanging) {
_syncControllerOffset();
}
}
_scrollUnderwayCount -= 1;
return false;
}
bool _debugScheduleCheckHasValidChildrenCount() {
if (_debugHasScheduledValidChildrenCountCheck) {
return true;
}
WidgetsBinding.instance.addPostFrameCallback((Duration duration) {
_debugHasScheduledValidChildrenCountCheck = false;
if (!mounted) {
return;
}
assert(() {
if (_controller!.length != widget.children.length) {
throw FlutterError(
"Controller's length property (${_controller!.length}) does not match the "
"number of children (${widget.children.length}) present in TabBarView's children property.",
);
}
return true;
}());
}, debugLabel: 'TabBarView.validChildrenCountCheck');
_debugHasScheduledValidChildrenCountCheck = true;
return true;
}
@override
Widget build(BuildContext context) {
assert(_debugScheduleCheckHasValidChildrenCount());
return NotificationListener<ScrollNotification>(
onNotification: _handleScrollNotification,
child: PageView(
scrollDirection: widget.scrollDirection,
dragStartBehavior: widget.dragStartBehavior,
clipBehavior: widget.clipBehavior,
controller: _pageController,
physics: widget.physics == null
? const PageScrollPhysics().applyTo(const ClampingScrollPhysics())
: const PageScrollPhysics().applyTo(widget.physics),
children: _childrenWithKey,
),
);
}
}

View File

@@ -3,7 +3,6 @@ import 'package:PiliPlus/common/style.dart';
import 'package:PiliPlus/models/common/image_type.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:PiliPlus/utils/image_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:cached_network_image/cached_network_image.dart';
import 'package:flutter/material.dart';
@@ -37,9 +36,6 @@ class NetworkImgLayer extends StatelessWidget {
final Alignment alignment;
final bool? cacheWidth;
static Color? reduceLuxColor = Pref.reduceLuxColor;
static bool reduce = false;
@override
Widget build(BuildContext context) {
final isEmote = type == ImageType.emote;
@@ -74,8 +70,6 @@ class NetworkImgLayer extends StatelessWidget {
imageUrl: ImageUtils.thumbnailUrl(
src,
maxQuality: quality,
/// remove gif
suffix: src!.endsWith(ImageUtils.kSuffixGIF)
? ImageUtils.kSuffixJPG
: ImageUtils.kSuffixWEBP,
@@ -94,8 +88,6 @@ class NetworkImgLayer extends StatelessWidget {
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
errorWidget: (_, _, _) =>
_placeholder(context, isEmote: isEmote, isAvatar: isAvatar),
colorBlendMode: reduce ? BlendMode.modulate : null,
color: reduce ? reduceLuxColor : null,
);
}
@@ -121,8 +113,6 @@ class NetworkImgLayer extends StatelessWidget {
width: width,
height: height,
cacheWidth: width.cacheSize(context),
colorBlendMode: reduce ? BlendMode.modulate : null,
color: reduce ? reduceLuxColor : null,
),
),
);

View File

@@ -22,7 +22,7 @@ import 'package:PiliPlus/common/widgets/gesture/horizontal_drag_gesture_recogniz
import 'package:PiliPlus/common/widgets/gesture/image_horizontal_drag_gesture_recognizer.dart';
import 'package:PiliPlus/utils/extension/num_ext.dart';
import 'package:easy_debounce/easy_throttle.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/foundation.dart' show clampDouble;
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
import 'package:flutter/physics.dart' show FrictionSimulation;

View File

@@ -1,4 +1,5 @@
import 'package:flutter/foundation.dart';
import 'package:flutter/foundation.dart'
show kDebugMode, describeIdentity, ValueListenable;
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';