merge: 修正进度拖动与底栏联动
This commit is contained in:
commit
3690fb1bc4
9 files changed
+59
-87
No files matched your search
@@ -1183,6 +1183,7 @@ $ flutter test
|
|||||||
- 按最新反馈移除整行榜单与热度胶囊,信息顺序收敛为标题、剧名、标签、简介、观看全集。
|
- 按最新反馈移除整行榜单与热度胶囊,信息顺序收敛为标题、剧名、标签、简介、观看全集。
|
||||||
- 剧名 19/w600,箭头 20 白色并紧邻剧名;标签行改为 13/w600 亮灰内联布局。
|
- 剧名 19/w600,箭头 20 白色并紧邻剧名;标签行改为 13/w600 亮灰内联布局。
|
||||||
- 简介「展开/收起」沿用现有三语文案;进度条热区恢复 24 并接入拖动自动清屏与预览卡片。
|
- 简介「展开/收起」沿用现有三语文案;进度条热区恢复 24 并接入拖动自动清屏与预览卡片。
|
||||||
- 拖动期间隐藏操作栏、文字及根底栏,顶部导航常驻;松手后持续清屏直到点击画面。
|
- 拖动仅控制视频浮层内容,顶部导航与根底栏保持常驻。
|
||||||
- 进度条固定中心并动画到 6 高,时间气泡限制在左右 12;松手恢复拖动前浮层状态。
|
- 进度条固定中心并动画到 6 高,时间气泡限制在左右 12;end/cancel/pointer 兜底均恢复拖动前状态。
|
||||||
- 修复 `scrubCancelRequest` 误置于 `initState` 的编译错误,并清理推荐页未使用变量;`flutter analyze` 无问题。
|
- 修复 `scrubCancelRequest` 误置于 `initState` 的编译错误,并清理推荐页未使用变量;`flutter analyze` 无问题。
|
||||||
|
- 观看全集按钮相对进度条上移 8,间距调整为 20;`flutter analyze` 无问题。
|
||||||
@@ -23,7 +23,6 @@ class HomeLogic extends ChangeNotifier {
|
|||||||
bool drawerOpen = false;
|
bool drawerOpen = false;
|
||||||
bool detailOpen = false;
|
bool detailOpen = false;
|
||||||
bool videoImmersive = false;
|
bool videoImmersive = false;
|
||||||
bool scrubHidden = false;
|
|
||||||
bool _dramaNotifyScheduled = false;
|
bool _dramaNotifyScheduled = false;
|
||||||
bool _disposed = false;
|
bool _disposed = false;
|
||||||
|
|
||||||
@@ -145,12 +144,6 @@ class HomeLogic extends ChangeNotifier {
|
|||||||
notify();
|
notify();
|
||||||
}
|
}
|
||||||
|
|
||||||
void onScrubVisibilityChanged(bool value) {
|
|
||||||
if (scrubHidden == value) return;
|
|
||||||
scrubHidden = value;
|
|
||||||
notify();
|
|
||||||
}
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void dispose() {
|
void dispose() {
|
||||||
_disposed = true;
|
_disposed = true;
|
||||||
|
|||||||
@@ -239,15 +239,7 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
backgroundColor: AppColors.transparent,
|
backgroundColor: AppColors.transparent,
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
body: _body(context),
|
body: _body(context),
|
||||||
bottomNavigationBar: logic.videoImmersive
|
bottomNavigationBar: logic.videoImmersive ? null : _nav(context),
|
||||||
? null
|
|
||||||
: Visibility(
|
|
||||||
visible: !logic.scrubHidden,
|
|
||||||
maintainSize: true,
|
|
||||||
maintainAnimation: true,
|
|
||||||
maintainState: true,
|
|
||||||
child: _nav(context),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
return AnnotatedRegion<SystemUiOverlayStyle>(
|
return AnnotatedRegion<SystemUiOverlayStyle>(
|
||||||
@@ -296,7 +288,6 @@ class _HomeTabsState extends State<_HomeTabs> {
|
|||||||
active: logic.tab == 1,
|
active: logic.tab == 1,
|
||||||
onSearch: () => _openSearch(context),
|
onSearch: () => _openSearch(context),
|
||||||
onOpenFilter: () => _pushPage(context, const FilterPage()),
|
onOpenFilter: () => _pushPage(context, const FilterPage()),
|
||||||
onScrubVisibilityChanged: logic.onScrubVisibilityChanged,
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -914,15 +914,19 @@ class PlayerLogic extends ChangeNotifier {
|
|||||||
void beginScrub(VideoPlayerPort player) {
|
void beginScrub(VideoPlayerPort player) {
|
||||||
if (session.active != player) return;
|
if (session.active != player) return;
|
||||||
scrubbingPlayer = player;
|
scrubbingPlayer = player;
|
||||||
session.setOverlayOpen(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cancelScrub() {
|
void cancelScrub() {
|
||||||
if (scrubbingPlayer == null) return;
|
if (scrubbingPlayer == null) return;
|
||||||
scrubbingPlayer = null;
|
scrubbingPlayer = null;
|
||||||
session.setOverlayOpen(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Future<void> endScrub(
|
||||||
|
BuildContext context,
|
||||||
|
VideoPlayerPort player,
|
||||||
|
Duration position,
|
||||||
|
) => seekTo(context, player, position);
|
||||||
|
|
||||||
Future<void> seekTo(
|
Future<void> seekTo(
|
||||||
BuildContext context,
|
BuildContext context,
|
||||||
VideoPlayerPort player,
|
VideoPlayerPort player,
|
||||||
|
|||||||
@@ -70,7 +70,6 @@ class PlayerPage extends StatefulWidget {
|
|||||||
this.showHomeFeedHeader = true,
|
this.showHomeFeedHeader = true,
|
||||||
this.onDramaChanged,
|
this.onDramaChanged,
|
||||||
this.onImmersiveChanged,
|
this.onImmersiveChanged,
|
||||||
this.onScrubVisibilityChanged,
|
|
||||||
this.onOpenFullPlayer,
|
this.onOpenFullPlayer,
|
||||||
this.onRefreshFeed,
|
this.onRefreshFeed,
|
||||||
this.onLoadMore,
|
this.onLoadMore,
|
||||||
@@ -97,7 +96,6 @@ class PlayerPage extends StatefulWidget {
|
|||||||
final bool showHomeFeedHeader;
|
final bool showHomeFeedHeader;
|
||||||
final ValueChanged<Drama>? onDramaChanged;
|
final ValueChanged<Drama>? onDramaChanged;
|
||||||
final ValueChanged<bool>? onImmersiveChanged;
|
final ValueChanged<bool>? onImmersiveChanged;
|
||||||
final ValueChanged<bool>? onScrubVisibilityChanged;
|
|
||||||
final Future<void> Function(Drama drama, Episode episode)? onOpenFullPlayer;
|
final Future<void> Function(Drama drama, Episode episode)? onOpenFullPlayer;
|
||||||
final Future<bool> Function()? onRefreshFeed;
|
final Future<bool> Function()? onRefreshFeed;
|
||||||
final Future<void> Function()? onLoadMore;
|
final Future<void> Function()? onLoadMore;
|
||||||
@@ -273,7 +271,6 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
void _hideChrome() {
|
void _hideChrome() {
|
||||||
if (!_chromeVisible) return;
|
if (!_chromeVisible) return;
|
||||||
setState(() => _chromeVisible = false);
|
setState(() => _chromeVisible = false);
|
||||||
widget.onScrubVisibilityChanged?.call(true);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 长按两侧:切 2 倍速并清屏,记下进入前的状态用于松手恢复。
|
/// 长按两侧:切 2 倍速并清屏,记下进入前的状态用于松手恢复。
|
||||||
@@ -288,7 +285,6 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
_playbackSpeed = _boostPlaybackSpeed;
|
_playbackSpeed = _boostPlaybackSpeed;
|
||||||
_chromeVisible = false;
|
_chromeVisible = false;
|
||||||
});
|
});
|
||||||
widget.onScrubVisibilityChanged?.call(true);
|
|
||||||
unawaited(logic.setPlaybackSpeed(_boostPlaybackSpeed));
|
unawaited(logic.setPlaybackSpeed(_boostPlaybackSpeed));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -304,14 +300,12 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
_playbackSpeed = speed;
|
_playbackSpeed = speed;
|
||||||
_chromeVisible = chrome;
|
_chromeVisible = chrome;
|
||||||
});
|
});
|
||||||
widget.onScrubVisibilityChanged?.call(!chrome);
|
|
||||||
unawaited(logic.setPlaybackSpeed(speed));
|
unawaited(logic.setPlaybackSpeed(speed));
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setScrubbing(bool value) {
|
void _setScrubbing(bool value) {
|
||||||
if (_scrubbing == value) return;
|
if (_scrubbing == value) return;
|
||||||
setState(() => _scrubbing = value);
|
setState(() => _scrubbing = value);
|
||||||
widget.onScrubVisibilityChanged?.call(value);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _finishFeedScrub(bool wasVisible) {
|
void _finishFeedScrub(bool wasVisible) {
|
||||||
@@ -319,7 +313,6 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
_scrubbing = false;
|
_scrubbing = false;
|
||||||
_chromeVisible = wasVisible;
|
_chromeVisible = wasVisible;
|
||||||
});
|
});
|
||||||
widget.onScrubVisibilityChanged?.call(!wasVisible);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _cancelFeedScrub() {
|
void _cancelFeedScrub() {
|
||||||
@@ -333,7 +326,6 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
_scrubbing = false;
|
_scrubbing = false;
|
||||||
_chromeVisible = true;
|
_chromeVisible = true;
|
||||||
});
|
});
|
||||||
widget.onScrubVisibilityChanged?.call(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleFeedSurfaceTap() {
|
void _handleFeedSurfaceTap() {
|
||||||
@@ -676,7 +668,7 @@ class _PlayerPageState extends State<PlayerPage>
|
|||||||
onScrubVisibilityChanged: _setScrubbing,
|
onScrubVisibilityChanged: _setScrubbing,
|
||||||
cancelScrubRequest: widget.scrubCancelRequest,
|
cancelScrubRequest: widget.scrubCancelRequest,
|
||||||
onSeek: ready
|
onSeek: ready
|
||||||
? (position) => logic.seekTo(context, videoPort!, position)
|
? (position) => logic.endScrub(context, videoPort!, position)
|
||||||
: null,
|
: null,
|
||||||
thumbnailService: _thumbnailService,
|
thumbnailService: _thumbnailService,
|
||||||
spriteAxisService: _spriteAxisService,
|
spriteAxisService: _spriteAxisService,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ const double _progressHitHeight = 28;
|
|||||||
const double _pageHorizontal = 14;
|
const double _pageHorizontal = 14;
|
||||||
const double _railRight = 8;
|
const double _railRight = 8;
|
||||||
const double _railGap = 12;
|
const double _railGap = 12;
|
||||||
|
const double _bottomInfoInset = 20;
|
||||||
const double _railBottomOffset = 60;
|
const double _railBottomOffset = 60;
|
||||||
const List<Shadow> _boostTextShadows = [
|
const List<Shadow> _boostTextShadows = [
|
||||||
Shadow(color: AppColors.shadow, blurRadius: 5, offset: Offset(0, 1)),
|
Shadow(color: AppColors.shadow, blurRadius: 5, offset: Offset(0, 1)),
|
||||||
@@ -141,7 +142,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
|
|||||||
Positioned(
|
Positioned(
|
||||||
left: _pageHorizontal,
|
left: _pageHorizontal,
|
||||||
right: _railRight,
|
right: _railRight,
|
||||||
bottom: 12,
|
bottom: _bottomInfoInset,
|
||||||
child: Row(
|
child: Row(
|
||||||
crossAxisAlignment: CrossAxisAlignment.end,
|
crossAxisAlignment: CrossAxisAlignment.end,
|
||||||
children: [
|
children: [
|
||||||
@@ -184,6 +185,7 @@ class _HomeFeedOverlayState extends State<HomeFeedOverlay> {
|
|||||||
void _endScrub() {
|
void _endScrub() {
|
||||||
final wasVisible = _wasVisibleBeforeScrub;
|
final wasVisible = _wasVisibleBeforeScrub;
|
||||||
if (_scrubbing) setState(() => _scrubbing = false);
|
if (_scrubbing) setState(() => _scrubbing = false);
|
||||||
|
widget.onScrubVisibilityChanged?.call(false);
|
||||||
widget.onScrubEnd?.call(wasVisible);
|
widget.onScrubEnd?.call(wasVisible);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
double? _preview;
|
double? _preview;
|
||||||
Timer? _bufferTimer;
|
Timer? _bufferTimer;
|
||||||
bool _buffering = false;
|
bool _buffering = false;
|
||||||
|
bool _dragging = false;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
@@ -61,6 +62,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
_attachSource();
|
_attachSource();
|
||||||
}
|
}
|
||||||
if (oldWidget.cancelScrubRequest != widget.cancelScrubRequest) {
|
if (oldWidget.cancelScrubRequest != widget.cancelScrubRequest) {
|
||||||
|
_dragging = false;
|
||||||
_preview = null;
|
_preview = null;
|
||||||
}
|
}
|
||||||
if (oldWidget.locked != widget.locked) {
|
if (oldWidget.locked != widget.locked) {
|
||||||
@@ -68,6 +70,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
_bufferTimer = null;
|
_bufferTimer = null;
|
||||||
_buffering = false;
|
_buffering = false;
|
||||||
if (widget.locked) {
|
if (widget.locked) {
|
||||||
|
_dragging = false;
|
||||||
_preview = null;
|
_preview = null;
|
||||||
} else {
|
} else {
|
||||||
_syncBufferState(notify: false);
|
_syncBufferState(notify: false);
|
||||||
@@ -88,7 +91,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
builder: (context, constraints) {
|
builder: (context, constraints) {
|
||||||
final width = constraints.maxWidth;
|
final width = constraints.maxWidth;
|
||||||
final source = widget.controller;
|
final source = widget.controller;
|
||||||
final scrubbing = _preview != null;
|
final scrubbing = _dragging;
|
||||||
final loading = !widget.locked && !scrubbing && _buffering;
|
final loading = !widget.locked && !scrubbing && _buffering;
|
||||||
final track = widget.locked
|
final track = widget.locked
|
||||||
? _inactiveTrack()
|
? _inactiveTrack()
|
||||||
@@ -115,34 +118,25 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
!loading &&
|
!loading &&
|
||||||
(source?.value.isInitialized ?? false);
|
(source?.value.isInitialized ?? false);
|
||||||
final video = source?.value;
|
final video = source?.value;
|
||||||
final previewPosition = _preview == null || video == null
|
final previewPosition = !_dragging || _preview == null || video == null
|
||||||
? null
|
? null
|
||||||
: seekPositionForFraction(_preview!, video.duration);
|
: seekPositionForFraction(_preview!, video.duration);
|
||||||
final showPreview = previewPosition != null;
|
final showPreview = previewPosition != null;
|
||||||
return GestureDetector(
|
return Listener(
|
||||||
|
behavior: HitTestBehavior.opaque,
|
||||||
|
onPointerUp: (_) => _finishScrub(),
|
||||||
|
onPointerCancel: (_) => _finishScrub(),
|
||||||
|
child: GestureDetector(
|
||||||
key: const Key('home-feed-progress'),
|
key: const Key('home-feed-progress'),
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onHorizontalDragStart: interactive
|
onHorizontalDragStart: interactive
|
||||||
? (details) {
|
? (details) => _startScrub(details.localPosition.dx / width)
|
||||||
widget.onScrubStart?.call();
|
|
||||||
_update(details.localPosition.dx / width);
|
|
||||||
}
|
|
||||||
: null,
|
: null,
|
||||||
onHorizontalDragUpdate: interactive
|
onHorizontalDragUpdate: interactive
|
||||||
? (details) => _update(details.localPosition.dx / width)
|
? (details) => _update(details.localPosition.dx / width)
|
||||||
: null,
|
: null,
|
||||||
onHorizontalDragEnd: interactive
|
onHorizontalDragEnd: interactive ? (_) => _finishScrub() : null,
|
||||||
? (_) {
|
onHorizontalDragCancel: interactive ? _finishScrub : null,
|
||||||
widget.onScrubEnd?.call();
|
|
||||||
_commit(_preview);
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
onHorizontalDragCancel: interactive
|
|
||||||
? () {
|
|
||||||
widget.onScrubEnd?.call();
|
|
||||||
_cancelPreview();
|
|
||||||
}
|
|
||||||
: null,
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
@@ -159,6 +153,7 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
),
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -259,23 +254,32 @@ class _FeedProgressBarState extends State<_FeedProgressBar> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void _startScrub(double fraction) {
|
||||||
|
if (_dragging) return;
|
||||||
|
setState(() {
|
||||||
|
_dragging = true;
|
||||||
|
_preview = fraction.clamp(0.0, 1.0).toDouble();
|
||||||
|
});
|
||||||
|
widget.onScrubStart?.call();
|
||||||
|
}
|
||||||
|
|
||||||
void _update(double fraction) {
|
void _update(double fraction) {
|
||||||
|
if (!_dragging) return;
|
||||||
setState(() => _preview = fraction.clamp(0.0, 1.0).toDouble());
|
setState(() => _preview = fraction.clamp(0.0, 1.0).toDouble());
|
||||||
}
|
}
|
||||||
|
|
||||||
void _commit(double? fraction) {
|
void _finishScrub() {
|
||||||
|
if (!_dragging) return;
|
||||||
|
final fraction = _preview;
|
||||||
|
setState(() {
|
||||||
|
_dragging = false;
|
||||||
|
_preview = null;
|
||||||
|
});
|
||||||
|
widget.onScrubEnd?.call();
|
||||||
if (widget.locked || fraction == null) return;
|
if (widget.locked || fraction == null) return;
|
||||||
final total = widget.controller?.value.duration.inMilliseconds ?? 0;
|
final total = widget.controller?.value.duration.inMilliseconds ?? 0;
|
||||||
if (total > 0) {
|
if (total <= 0) return;
|
||||||
widget.onSeek?.call(
|
widget.onSeek?.call(Duration(milliseconds: (total * fraction).round()));
|
||||||
Duration(milliseconds: (total * fraction.clamp(0.0, 1.0)).round()),
|
|
||||||
);
|
|
||||||
}
|
|
||||||
setState(() => _preview = null);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _cancelPreview() {
|
|
||||||
setState(() => _preview = null);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _track(double fraction, double width) {
|
Widget _track(double fraction, double width) {
|
||||||
|
|||||||
@@ -28,14 +28,12 @@ class RecommendPage extends StatefulWidget {
|
|||||||
required this.active,
|
required this.active,
|
||||||
required this.onSearch,
|
required this.onSearch,
|
||||||
required this.onOpenFilter,
|
required this.onOpenFilter,
|
||||||
required this.onScrubVisibilityChanged,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
final HomeFeedController feedController;
|
final HomeFeedController feedController;
|
||||||
final bool active;
|
final bool active;
|
||||||
final VoidCallback onSearch;
|
final VoidCallback onSearch;
|
||||||
final VoidCallback onOpenFilter;
|
final VoidCallback onOpenFilter;
|
||||||
final ValueChanged<bool> onScrubVisibilityChanged;
|
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<RecommendPage> createState() => _RecommendPageState();
|
State<RecommendPage> createState() => _RecommendPageState();
|
||||||
@@ -43,7 +41,6 @@ class RecommendPage extends StatefulWidget {
|
|||||||
|
|
||||||
class _RecommendPageState extends State<RecommendPage> {
|
class _RecommendPageState extends State<RecommendPage> {
|
||||||
RecommendInnerTab _tab = RecommendInnerTab.feed;
|
RecommendInnerTab _tab = RecommendInnerTab.feed;
|
||||||
bool _scrubbing = false;
|
|
||||||
int _scrubCancelRequest = 0;
|
int _scrubCancelRequest = 0;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
@@ -159,38 +156,22 @@ class _RecommendPageState extends State<RecommendPage> {
|
|||||||
_openDrama(drama, episodeId: episode.id),
|
_openDrama(drama, episodeId: episode.id),
|
||||||
onRefreshFeed: widget.feedController.refreshCurrent,
|
onRefreshFeed: widget.feedController.refreshCurrent,
|
||||||
onLoadMore: widget.feedController.loadMore,
|
onLoadMore: widget.feedController.loadMore,
|
||||||
onScrubVisibilityChanged: _setScrubbing,
|
|
||||||
scrubCancelRequest: _scrubCancelRequest,
|
scrubCancelRequest: _scrubCancelRequest,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
void _selectTab(RecommendInnerTab tab) {
|
void _selectTab(RecommendInnerTab tab) {
|
||||||
final wasScrubbing = _scrubbing;
|
|
||||||
setState(() {
|
setState(() {
|
||||||
_tab = tab;
|
_tab = tab;
|
||||||
if (wasScrubbing) _scrubCancelRequest++;
|
_scrubCancelRequest++;
|
||||||
_scrubbing = false;
|
|
||||||
});
|
});
|
||||||
if (wasScrubbing) widget.onScrubVisibilityChanged(false);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void _handleSearch() {
|
void _handleSearch() {
|
||||||
if (_scrubbing) {
|
setState(() => _scrubCancelRequest++);
|
||||||
setState(() {
|
|
||||||
_scrubbing = false;
|
|
||||||
_scrubCancelRequest++;
|
|
||||||
});
|
|
||||||
widget.onScrubVisibilityChanged(false);
|
|
||||||
}
|
|
||||||
widget.onSearch();
|
widget.onSearch();
|
||||||
}
|
}
|
||||||
|
|
||||||
void _setScrubbing(bool value) {
|
|
||||||
if (_scrubbing == value) return;
|
|
||||||
setState(() => _scrubbing = value);
|
|
||||||
widget.onScrubVisibilityChanged(value);
|
|
||||||
}
|
|
||||||
|
|
||||||
Widget _withTopNavSpace(Widget child) {
|
Widget _withTopNavSpace(Widget child) {
|
||||||
return SafeArea(
|
return SafeArea(
|
||||||
bottom: false,
|
bottom: false,
|
||||||
|
|||||||
@@ -102,15 +102,19 @@ void main() {
|
|||||||
await tester.pump(const Duration(milliseconds: 130));
|
await tester.pump(const Duration(milliseconds: 130));
|
||||||
expect(find.byKey(const Key('recommend-top-nav')), findsOneWidget);
|
expect(find.byKey(const Key('recommend-top-nav')), findsOneWidget);
|
||||||
expect(tester.getCenter(progress).dy, closeTo(progressCenterY, 0.1));
|
expect(tester.getCenter(progress).dy, closeTo(progressCenterY, 0.1));
|
||||||
final navVisibility = find.ancestor(
|
expect(find.byType(AppBottomNav), findsOneWidget);
|
||||||
of: find.byKey(const Key('home-tabs-bar')),
|
expect(
|
||||||
matching: find.byType(Visibility),
|
tester.getSize(find.byKey(const Key('home-tabs-bar'))).height,
|
||||||
|
AppDimens.navHeight,
|
||||||
);
|
);
|
||||||
expect(tester.widget<Visibility>(navVisibility.first).visible, isFalse);
|
|
||||||
await scrub.up();
|
await scrub.up();
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
expect(find.byKey(const Key('recommend-top-nav')), findsOneWidget);
|
expect(find.byKey(const Key('recommend-top-nav')), findsOneWidget);
|
||||||
expect(tester.widget<Visibility>(navVisibility.first).visible, isTrue);
|
expect(find.byType(AppBottomNav), findsOneWidget);
|
||||||
|
expect(
|
||||||
|
tester.getSize(find.byKey(const Key('home-tabs-bar'))).height,
|
||||||
|
AppDimens.navHeight,
|
||||||
|
);
|
||||||
|
|
||||||
await tester.tap(find.byKey(const Key('recommend-tab-playlist')));
|
await tester.tap(find.byKey(const Key('recommend-tab-playlist')));
|
||||||
await tester.pumpAndSettle();
|
await tester.pumpAndSettle();
|
||||||
|
|||||||
Reference in new issue
Block a user