opt: initialScrollIndex (#1018)

This commit is contained in:
My-Responsitories
2025-08-14 23:50:45 +08:00
committed by GitHub
parent 629be129ff
commit 1943b65788
4 changed files with 33 additions and 76 deletions

View File

@@ -20,7 +20,7 @@ import 'package:PiliPlus/models_new/pgc/pgc_info_model/episode.dart' as pgc;
import 'package:PiliPlus/models_new/video/video_detail/episode.dart' as ugc; import 'package:PiliPlus/models_new/video/video_detail/episode.dart' as ugc;
import 'package:PiliPlus/models_new/video/video_detail/page.dart'; import 'package:PiliPlus/models_new/video/video_detail/page.dart';
import 'package:PiliPlus/models_new/video/video_relation/data.dart'; import 'package:PiliPlus/models_new/video/video_relation/data.dart';
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart'; import 'package:PiliPlus/pages/common/slide/common_collapse_slide_page.dart';
import 'package:PiliPlus/pages/video/controller.dart'; import 'package:PiliPlus/pages/video/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart'; import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart';
@@ -36,7 +36,7 @@ import 'package:get/get.dart';
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart'; import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
import 'package:scrollable_positioned_list/scrollable_positioned_list.dart'; import 'package:scrollable_positioned_list/scrollable_positioned_list.dart';
class EpisodePanel extends CommonSlidePage { class EpisodePanel extends CommonCollapseSlidePage {
const EpisodePanel({ const EpisodePanel({
super.key, super.key,
super.enableSlide, super.enableSlide,
@@ -83,7 +83,7 @@ class EpisodePanel extends CommonSlidePage {
State<EpisodePanel> createState() => _EpisodePanelState(); State<EpisodePanel> createState() => _EpisodePanelState();
} }
class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> { class _EpisodePanelState extends CommonCollapseSlidePageState<EpisodePanel> {
// tab // tab
late final TabController _tabController = TabController( late final TabController _tabController = TabController(
initialIndex: widget.initialTabIndex, initialIndex: widget.initialTabIndex,
@@ -109,8 +109,6 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
// fav // fav
Rx<LoadingState>? _favState; Rx<LoadingState>? _favState;
late bool _isInit = true;
void listener() { void listener() {
_currentTabIndex.value = _tabController.index; _currentTabIndex.value = _tabController.index;
} }
@@ -123,8 +121,8 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
} }
void jumpToCurrent() { void jumpToCurrent() {
int newItemIndex = _findCurrentItemIndex; final newItemIndex = _findCurrentItemIndex;
if (_currentItemIndex != _findCurrentItemIndex) { if (_currentItemIndex != newItemIndex) {
_currentItemIndex = newItemIndex; _currentItemIndex = newItemIndex;
try { try {
_itemScrollController[_currentTabIndex.value].jumpTo( _itemScrollController[_currentTabIndex.value].jumpTo(
@@ -153,7 +151,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
widget.list.length, widget.list.length,
(_) => ItemScrollController(), (_) => ItemScrollController(),
); );
_isReversed = List.generate(widget.list.length, (_) => false); _isReversed = List.filled(widget.list.length, false);
if (widget.type == EpisodeType.season && Accounts.main.isLogin) { if (widget.type == EpisodeType.season && Accounts.main.isLogin) {
_favState = LoadingState.loading().obs; _favState = LoadingState.loading().obs;
@@ -168,20 +166,6 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
} }
_currentItemIndex = _findCurrentItemIndex; _currentItemIndex = _findCurrentItemIndex;
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
setState(() {
_isInit = false;
});
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
_itemScrollController[widget.initialTabIndex].jumpTo(
index: _currentItemIndex,
);
} catch (_) {}
});
}
});
} }
@override @override
@@ -192,17 +176,6 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
super.dispose(); super.dispose();
} }
@override
Widget build(BuildContext context) {
if (_isInit) {
return const CustomScrollView(
physics: NeverScrollableScrollPhysics(),
);
}
return super.build(context);
}
@override @override
Widget buildPage(ThemeData theme) { Widget buildPage(ThemeData theme) {
final isMulti = widget.type == EpisodeType.season && widget.list.length > 1; final isMulti = widget.type == EpisodeType.season && widget.list.length > 1;
@@ -281,6 +254,7 @@ class _EpisodePanelState extends CommonSlidePageState<EpisodePanel> {
), ),
reverse: _isReversed[tabIndex], reverse: _isReversed[tabIndex],
itemCount: episodes.length, itemCount: episodes.length,
initialScrollIndex: _currentItemIndex,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
itemBuilder: (BuildContext context, int itemIndex) { itemBuilder: (BuildContext context, int itemIndex) {
final episode = episodes[itemIndex]; final episode = episodes[itemIndex];

View File

@@ -50,34 +50,15 @@ class MediaListPanel extends CommonCollapseSlidePage {
class _MediaListPanelState class _MediaListPanelState
extends CommonCollapseSlidePageState<MediaListPanel> { extends CommonCollapseSlidePageState<MediaListPanel> {
final _scrollController = ItemScrollController(); late final int _index;
late RxBool desc; late final RxBool desc = widget.desc.obs;
@override @override
void initState() { void initState() {
super.initState(); super.initState();
desc = widget.desc.obs; final bvid = widget.getBvId();
} final bvIndex = widget.mediaList.indexWhere((item) => item.bvid == bvid);
_index = bvIndex == -1 ? 0 : bvIndex;
@override
void init() {
WidgetsBinding.instance.addPostFrameCallback((_) {
if (mounted) {
int index = widget.mediaList.indexWhere(
(item) => item.bvid == widget.getBvId(),
);
if (index > 0) {
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
_scrollController.jumpTo(index: index);
} catch (_) {}
});
}
setState(() {
isInit = false;
});
}
});
} }
@override @override
@@ -142,9 +123,9 @@ class _MediaListPanelState
() { () {
final showDelBtn = widget.onDelete != null && widget.mediaList.length > 1; final showDelBtn = widget.onDelete != null && widget.mediaList.length > 1;
return ScrollablePositionedList.separated( return ScrollablePositionedList.separated(
itemScrollController: _scrollController,
physics: const AlwaysScrollableScrollPhysics(), physics: const AlwaysScrollableScrollPhysics(),
itemCount: widget.mediaList.length, itemCount: widget.mediaList.length,
initialScrollIndex: _index,
padding: EdgeInsets.only( padding: EdgeInsets.only(
top: 7, top: 7,
bottom: MediaQuery.paddingOf(context).bottom + 80, bottom: MediaQuery.paddingOf(context).bottom + 80,

View File

@@ -7,6 +7,7 @@ import 'package:PiliPlus/pages/video/reply_new/view.dart';
import 'package:PiliPlus/utils/id_utils.dart'; import 'package:PiliPlus/utils/id_utils.dart';
import 'package:PiliPlus/utils/request_utils.dart'; import 'package:PiliPlus/utils/request_utils.dart';
import 'package:PiliPlus/utils/storage_pref.dart'; import 'package:PiliPlus/utils/storage_pref.dart';
import 'package:fixnum/fixnum.dart';
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
import 'package:get/get.dart'; import 'package:get/get.dart';
import 'package:get/get_navigation/src/dialog/dialog_route.dart'; import 'package:get/get_navigation/src/dialog/dialog_route.dart';
@@ -72,26 +73,26 @@ class VideoReplyReplyController extends ReplyController
firstFloor = data.root; firstFloor = data.root;
} }
if (id != null) { if (id != null) {
index = data.root.replies.indexWhere((item) => item.id.toInt() == id); final id64 = Int64(id!);
if (index == -1) { final index = data.root.replies.indexWhere((item) => item.id == id64);
index = null; if (index != -1) {
} else { this.index = index;
controller = AnimationController( controller = AnimationController(
duration: const Duration(milliseconds: 300), duration: const Duration(milliseconds: 300),
vsync: this, vsync: this,
); );
WidgetsBinding.instance.addPostFrameCallback((_) async { WidgetsBinding.instance.addPostFrameCallback((_) async {
if (index != null) { try {
try { itemScrollCtr.jumpTo(
itemScrollCtr.jumpTo( index: hasRoot ? index + 3 : index + 1,
index: hasRoot ? index! + 3 : index! + 1, alignment: 0.25,
alignment: 0.25, );
); await Future.delayed(
await Future.delayed(const Duration(milliseconds: 800)); const Duration(milliseconds: 800),
await controller?.forward(); controller?.forward,
index = null; );
} catch (_) {} this.index = null;
} } catch (_) {}
}); });
} }
id = null; id = null;

View File

@@ -321,6 +321,7 @@ class _VideoReplyReplyPanelState
), ),
); );
} else { } else {
final child = _replyItem(response[index], index);
if (_controller.index != null && _controller.index == index) { if (_controller.index != null && _controller.index == index) {
colorAnimation ??= ColorTween( colorAnimation ??= ColorTween(
begin: theme.colorScheme.onInverseSurface, begin: theme.colorScheme.onInverseSurface,
@@ -328,17 +329,17 @@ class _VideoReplyReplyPanelState
).animate(_controller.controller!); ).animate(_controller.controller!);
return AnimatedBuilder( return AnimatedBuilder(
animation: colorAnimation!, animation: colorAnimation!,
builder: (context, child) { builder: (context, _) {
return ColoredBox( return ColoredBox(
color: color:
colorAnimation!.value ?? colorAnimation!.value ??
theme.colorScheme.onInverseSurface, theme.colorScheme.onInverseSurface,
child: _replyItem(response[index], index), child: child,
); );
}, },
); );
} }
return _replyItem(response[index], index); return child;
} }
}, },
), ),