diff --git a/lib/pages/common/reply_controller.dart b/lib/pages/common/reply_controller.dart index ea148f01f..eaaa6d6dd 100644 --- a/lib/pages/common/reply_controller.dart +++ b/lib/pages/common/reply_controller.dart @@ -55,7 +55,8 @@ abstract class ReplyController extends CommonListController { @override void checkIsEnd(int length) { - if (count.value != -1 && length >= count.value) { + final count = this.count.value; + if (count != -1 && length >= count) { isEnd = true; } } diff --git a/lib/pages/dynamics/view.dart b/lib/pages/dynamics/view.dart index 77cefe8e7..27b9e1baf 100644 --- a/lib/pages/dynamics/view.dart +++ b/lib/pages/dynamics/view.dart @@ -87,10 +87,10 @@ class _DynamicsPageState extends State height: isTop ? 76 : null, child: Obx( () { - if (_dynamicsController.upData.value.upList == null && - _dynamicsController.upData.value.liveUsers == null) { + final upData = _dynamicsController.upData.value; + if (upData.upList == null && upData.liveUsers == null) { return const SizedBox.shrink(); - } else if (_dynamicsController.upData.value.errMsg != null) { + } else if (upData.errMsg != null) { return Center( child: IconButton( icon: const Icon(Icons.refresh), diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index 9f5584cda..5b5593bc2 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -20,18 +20,19 @@ class UpPanel extends StatefulWidget { } class _UpPanelState extends State { - List? get upList => widget.dynamicsController.upData.value.upList; - List? get liveList => - widget.dynamicsController.upData.value.liveUsers?.items; late final isTop = widget.dynamicsController.upPanelPosition == UpPanelPosition.top; @override Widget build(BuildContext context) { - final theme = Theme.of(context); - if (!widget.dynamicsController.accountService.isLogin.value) { + final accountService = widget.dynamicsController.accountService; + if (!accountService.isLogin.value) { return const SizedBox.shrink(); } + final theme = Theme.of(context); + final upData = widget.dynamicsController.upData.value; + final List? upList = upData.upList; + final List? liveList = upData.liveUsers?.items; return CustomScrollView( scrollDirection: isTop ? Axis.horizontal : Axis.vertical, physics: const AlwaysScrollableScrollPhysics(), @@ -57,8 +58,7 @@ class _UpPanelState extends State { TextSpan( children: [ TextSpan( - text: - 'Live(${widget.dynamicsController.upData.value.liveUsers?.count ?? 0})', + text: 'Live(${upData.liveUsers?.count ?? 0})', ), if (!isTop) ...[ const TextSpan(text: '\n'), @@ -94,7 +94,7 @@ class _UpPanelState extends State { SliverList.builder( itemCount: liveList!.length, itemBuilder: (context, index) { - return upItemBuild(theme, liveList![index]); + return upItemBuild(theme, liveList[index]); }, ), SliverToBoxAdapter( @@ -106,8 +106,8 @@ class _UpPanelState extends State { theme, UpItem( uname: '我', - face: widget.dynamicsController.accountService.face.value, - mid: widget.dynamicsController.accountService.mid, + face: accountService.face.value, + mid: accountService.mid, ), ), ), @@ -116,7 +116,7 @@ class _UpPanelState extends State { SliverList.builder( itemCount: upList!.length, itemBuilder: (context, index) { - return upItemBuild(theme, upList![index]); + return upItemBuild(theme, upList[index]); }, ), if (!isTop) const SliverToBoxAdapter(child: SizedBox(height: 200)), diff --git a/lib/pages/dynamics_topic/view.dart b/lib/pages/dynamics_topic/view.dart index 2ff926fd5..111443ced 100644 --- a/lib/pages/dynamics_topic/view.dart +++ b/lib/pages/dynamics_topic/view.dart @@ -70,8 +70,8 @@ class _DynTopicPageState extends State { slivers: [ Obx(() => _buildAppBar(theme, _controller.topState.value)), Obx(() { - if (_controller.topicSortByConf.value?.allSortBy?.isNotEmpty == - true) { + final allSortBy = _controller.topicSortByConf.value?.allSortBy; + if (allSortBy != null && allSortBy.isNotEmpty) { return SliverPersistentHeader( pinned: true, delegate: CustomSliverPersistentHeaderDelegate( @@ -94,18 +94,13 @@ class _DynTopicPageState extends State { borderRadius: const BorderRadius.all(Radius.circular(25)), onPressed: (index) { - _controller.onSort(_controller.topicSortByConf - .value!.allSortBy![index].sortBy!); + _controller.onSort(allSortBy[index].sortBy!); (context as Element).markNeedsBuild(); }, - isSelected: _controller - .topicSortByConf.value!.allSortBy! - .map((e) { + isSelected: allSortBy.map((e) { return e.sortBy == _controller.sortBy; }).toList(), - children: _controller - .topicSortByConf.value!.allSortBy! - .map((e) { + children: allSortBy.map((e) { return Text( e.sortName!, style: const TextStyle( diff --git a/lib/pages/episode_panel/view.dart b/lib/pages/episode_panel/view.dart index cecdf0c8f..c33d9a737 100644 --- a/lib/pages/episode_panel/view.dart +++ b/lib/pages/episode_panel/view.dart @@ -593,8 +593,9 @@ class _EpisodePanelState extends CommonSlidePageState { icon: Icons.vertical_align_top, onPressed: () { try { - _itemScrollController[_currentTabIndex.value].scrollTo( - index: !_isReversed[_currentTabIndex.value] + final currentTabIndex = _currentTabIndex.value; + _itemScrollController[currentTabIndex].scrollTo( + index: !_isReversed[currentTabIndex] ? 0 : _getCurrEpisodes.length - 1, duration: const Duration(milliseconds: 200), @@ -609,8 +610,9 @@ class _EpisodePanelState extends CommonSlidePageState { icon: Icons.vertical_align_bottom, onPressed: () { try { - _itemScrollController[_currentTabIndex.value].scrollTo( - index: !_isReversed[_currentTabIndex.value] + final currentTabIndex = _currentTabIndex.value; + _itemScrollController[currentTabIndex].scrollTo( + index: !_isReversed[currentTabIndex] ? _getCurrEpisodes.length - 1 : 0, duration: const Duration(milliseconds: 200), @@ -625,11 +627,12 @@ class _EpisodePanelState extends CommonSlidePageState { icon: Icons.my_location, onPressed: () async { try { - if (_currentTabIndex.value != widget.initialTabIndex) { + final currentTabIndex = _currentTabIndex.value; + if (currentTabIndex != widget.initialTabIndex) { _tabController.animateTo(widget.initialTabIndex); await Future.delayed(const Duration(milliseconds: 225)); } - _itemScrollController[_currentTabIndex.value].scrollTo( + _itemScrollController[currentTabIndex].scrollTo( index: _currentItemIndex, duration: const Duration(milliseconds: 200), ); @@ -646,16 +649,19 @@ class _EpisodePanelState extends CommonSlidePageState { ), const Spacer(), Obx( - () => mediumButton( - tooltip: _isReversed[_currentTabIndex.value] ? '顺序' : '倒序', - icon: !_isReversed[_currentTabIndex.value] - ? MdiIcons.sortNumericAscending - : MdiIcons.sortNumericDescending, - onPressed: () => setState(() { - _isReversed[_currentTabIndex.value] = - !_isReversed[_currentTabIndex.value]; - }), - ), + () { + final currentTabIndex = _currentTabIndex.value; + return mediumButton( + tooltip: _isReversed[currentTabIndex] ? '顺序' : '倒序', + icon: !_isReversed[currentTabIndex] + ? MdiIcons.sortNumericAscending + : MdiIcons.sortNumericDescending, + onPressed: () => setState(() { + _isReversed[currentTabIndex] = + !_isReversed[currentTabIndex]; + }), + ); + }, ), if (widget.onClose != null) mediumButton( diff --git a/lib/pages/fav_detail/controller.dart b/lib/pages/fav_detail/controller.dart index e04669dda..d81f3a572 100644 --- a/lib/pages/fav_detail/controller.dart +++ b/lib/pages/fav_detail/controller.dart @@ -155,16 +155,17 @@ class FavDetailController if (element.bvid != list.first.bvid) { SmartDialog.showToast('已跳过不支持播放的视频'); } + final folderInfo = this.folderInfo.value; PageUtils.toVideoPage( 'bvid=${element.bvid}&cid=${element.ugc!.firstCid}', arguments: { 'videoItem': element, 'heroTag': Utils.makeHeroTag(element.bvid), 'sourceType': 'fav', - 'mediaId': folderInfo.value.id, + 'mediaId': folderInfo.id, 'oid': element.id, - 'favTitle': folderInfo.value.title, - 'count': folderInfo.value.mediaCount, + 'favTitle': folderInfo.title, + 'count': folderInfo.mediaCount, 'desc': true, 'isOwner': isOwner.value ?? false, }, diff --git a/lib/pages/fav_detail/view.dart b/lib/pages/fav_detail/view.dart index cfa00eabc..f71571c1c 100644 --- a/lib/pages/fav_detail/view.dart +++ b/lib/pages/fav_detail/view.dart @@ -45,53 +45,56 @@ class _FavDetailPageState extends State { Widget build(BuildContext context) { final theme = Theme.of(context); return Obx( - () => PopScope( - canPop: !_favDetailController.enableMultiSelect.value, - onPopInvokedWithResult: (didPop, result) { - if (_favDetailController.enableMultiSelect.value) { - _favDetailController.handleSelect(); - } - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - floatingActionButton: Obx( - () => _favDetailController.folderInfo.value.mediaCount > 0 - ? FloatingActionButton.extended( - onPressed: _favDetailController.toViewPlayAll, - label: const Text('播放全部'), - icon: const Icon(Icons.playlist_play), - ) - : const SizedBox.shrink(), - ), - body: SafeArea( - top: false, - bottom: false, - child: refreshIndicator( - onRefresh: _favDetailController.onRefresh, - child: CustomScrollView( - physics: const AlwaysScrollableScrollPhysics(), - controller: _favDetailController.scrollController, - slivers: [ - _buildHeader(theme), - SliverPadding( - padding: EdgeInsets.only( - bottom: MediaQuery.paddingOf(context).bottom + 85, + () { + final enableMultiSelect = _favDetailController.enableMultiSelect.value; + return PopScope( + canPop: !enableMultiSelect, + onPopInvokedWithResult: (didPop, result) { + if (enableMultiSelect) { + _favDetailController.handleSelect(); + } + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + floatingActionButton: Obx( + () => _favDetailController.folderInfo.value.mediaCount > 0 + ? FloatingActionButton.extended( + onPressed: _favDetailController.toViewPlayAll, + label: const Text('播放全部'), + icon: const Icon(Icons.playlist_play), + ) + : const SizedBox.shrink(), + ), + body: SafeArea( + top: false, + bottom: false, + child: refreshIndicator( + onRefresh: _favDetailController.onRefresh, + child: CustomScrollView( + physics: const AlwaysScrollableScrollPhysics(), + controller: _favDetailController.scrollController, + slivers: [ + _buildHeader(enableMultiSelect, theme), + SliverPadding( + padding: EdgeInsets.only( + bottom: MediaQuery.paddingOf(context).bottom + 85, + ), + sliver: Obx(() => _buildBody(enableMultiSelect, theme, + _favDetailController.loadingState.value)), ), - sliver: Obx(() => _buildBody( - theme, _favDetailController.loadingState.value)), - ), - ], + ], + ), ), ), ), - ), - ), + ); + }, ); } - Widget _buildHeader(ThemeData theme) { + Widget _buildHeader(bool enableMultiSelect, ThemeData theme) { return SliverAppBar.medium( - leading: _favDetailController.enableMultiSelect.value + leading: enableMultiSelect ? Row( children: [ IconButton( @@ -99,16 +102,20 @@ class _FavDetailPageState extends State { onPressed: _favDetailController.handleSelect, icon: const Icon(Icons.close_outlined), ), - Text( - '已选: ${_favDetailController.checkedCount.value}', - style: const TextStyle(fontSize: 15), + Obx( + () { + return Text( + '已选: ${_favDetailController.checkedCount.value}', + style: const TextStyle(fontSize: 15), + ); + }, ), ], ) : null, expandedHeight: kToolbarHeight + 130, pinned: true, - title: _favDetailController.enableMultiSelect.value + title: enableMultiSelect ? null : Column( crossAxisAlignment: CrossAxisAlignment.start, @@ -123,9 +130,7 @@ class _FavDetailPageState extends State { ) ], ), - actions: _favDetailController.enableMultiSelect.value - ? _selectActions(theme) - : _actions(theme), + actions: enableMultiSelect ? _selectActions(theme) : _actions(theme), flexibleSpace: _flexibleSpace(theme), ); } @@ -182,9 +187,10 @@ class _FavDetailPageState extends State { PopupMenuButton( icon: const Icon(Icons.more_vert), itemBuilder: (context) { + final isOwner = _favDetailController.isOwner.value ?? false; final folderInfo = _favDetailController.folderInfo.value; return [ - if (_favDetailController.isOwner.value == true) ...[ + if (isOwner) ...[ PopupMenuItem( onTap: _favDetailController.onSort, child: const Text('排序'), @@ -222,7 +228,7 @@ class _FavDetailPageState extends State { ), child: const Text('分享至动态'), ), - if (_favDetailController.isOwner.value == true) ...[ + if (isOwner) ...[ PopupMenuItem( onTap: _favDetailController.cleanFav, child: const Text('清除失效内容'), @@ -430,8 +436,8 @@ class _FavDetailPageState extends State { ); } - Widget _buildBody( - ThemeData theme, LoadingState?> loadingState) { + Widget _buildBody(bool enableMultiSelect, ThemeData theme, + LoadingState?> loadingState) { return switch (loadingState) { Loading() => SliverGrid( gridDelegate: Grid.videoCardHDelegate(context), @@ -461,6 +467,7 @@ class _FavDetailPageState extends State { ), ); } + final isOwner = _favDetailController.isOwner.value ?? false; FavDetailItemModel item = response[index]; return Stack( clipBehavior: Clip.none, @@ -468,7 +475,7 @@ class _FavDetailPageState extends State { Positioned.fill( child: FavVideoCardH( item: item, - onDelFav: _favDetailController.isOwner.value == true + onDelFav: isOwner ? () => _favDetailController.onCancelFav( index, item.id!, @@ -490,25 +497,22 @@ class _FavDetailPageState extends State { 'count': folderInfo.mediaCount, 'desc': true, 'isContinuePlaying': index != 0, - 'isOwner': - _favDetailController.isOwner.value ?? false, + 'isOwner': isOwner, }, ); }, - onTap: _favDetailController.enableMultiSelect.value + onTap: enableMultiSelect ? () => _favDetailController.onSelect(item) : null, - onLongPress: - _favDetailController.isOwner.value == true - ? () { - if (!_favDetailController - .enableMultiSelect.value) { - _favDetailController - .enableMultiSelect.value = true; - _favDetailController.onSelect(item); - } - } - : null, + onLongPress: isOwner + ? () { + if (!enableMultiSelect) { + _favDetailController + .enableMultiSelect.value = true; + _favDetailController.onSelect(item); + } + } + : null, ), ), Positioned( diff --git a/lib/pages/fav_panel/view.dart b/lib/pages/fav_panel/view.dart index b8b402a0c..824d91f26 100644 --- a/lib/pages/fav_panel/view.dart +++ b/lib/pages/fav_panel/view.dart @@ -43,13 +43,14 @@ class _FavPanelState extends State { } Widget get _buildBody { + late final list = widget.ctr.favFolderData.value.list!; return switch (loadingState) { Loading() => loadingWidget, Success() => ListView.builder( controller: widget.scrollController, - itemCount: widget.ctr.favFolderData.value.list!.length, + itemCount: list.length, itemBuilder: (context, index) { - FavFolderInfo item = widget.ctr.favFolderData.value.list![index]; + FavFolderInfo item = list[index]; return Material( type: MaterialType.transparency, child: Builder( diff --git a/lib/pages/history/base_controller.dart b/lib/pages/history/base_controller.dart index 2d9eff9e8..e1824e2da 100644 --- a/lib/pages/history/base_controller.dart +++ b/lib/pages/history/base_controller.dart @@ -51,10 +51,10 @@ class HistoryBaseController extends GetxController { showDialog( context: context, builder: (context) { + final pauseStatus = !this.pauseStatus.value; return AlertDialog( title: const Text('提示'), - content: - Text(!pauseStatus.value ? '啊叻?你要暂停历史记录功能吗?' : '啊叻?要恢复历史记录功能吗?'), + content: Text(pauseStatus ? '啊叻?你要暂停历史记录功能吗?' : '啊叻?要恢复历史记录功能吗?'), actions: [ TextButton( onPressed: Get.back, @@ -66,18 +66,17 @@ class HistoryBaseController extends GetxController { TextButton( onPressed: () async { SmartDialog.showLoading(msg: '请求中'); - var res = await UserHttp.pauseHistory(!pauseStatus.value); + var res = await UserHttp.pauseHistory(pauseStatus); SmartDialog.dismiss(); if (res.data['code'] == 0) { - SmartDialog.showToast( - !pauseStatus.value ? '暂停观看历史' : '恢复观看历史'); - pauseStatus.value = !pauseStatus.value; + SmartDialog.showToast(pauseStatus ? '暂停观看历史' : '恢复观看历史'); + this.pauseStatus.value = pauseStatus; GStorage.localCache - .put(LocalCacheKey.historyPause, pauseStatus.value); + .put(LocalCacheKey.historyPause, pauseStatus); } Get.back(); }, - child: Text(!pauseStatus.value ? '确认暂停' : '确认恢复'), + child: Text(pauseStatus ? '确认暂停' : '确认恢复'), ), ], ); diff --git a/lib/pages/history/view.dart b/lib/pages/history/view.dart index a9b84a3d4..3cc0f080d 100644 --- a/lib/pages/history/view.dart +++ b/lib/pages/history/view.dart @@ -44,9 +44,6 @@ class _HistoryPageState extends State return _historyController; } - bool get enableMultiSelect => - _historyController.baseCtr.enableMultiSelect.value; - @override void dispose() { Get.delete(); @@ -59,176 +56,182 @@ class _HistoryPageState extends State return widget.type != null ? _buildPage : Obx( - () => PopScope( - canPop: !enableMultiSelect, - onPopInvokedWithResult: (didPop, result) { - if (enableMultiSelect) { - currCtr().handleSelect(); - } - }, - child: Scaffold( - appBar: widget.type != null - ? null - : AppBarWidget( - visible: enableMultiSelect, - child1: AppBar( - title: const Text('观看记录'), - actions: [ - IconButton( - tooltip: '搜索', - onPressed: () => Get.toNamed('/historySearch'), - icon: const Icon(Icons.search_outlined), - ), - PopupMenuButton( - onSelected: (String type) { - // 处理菜单项选择的逻辑 - switch (type) { - case 'pause': - _historyController.baseCtr - .onPauseHistory(context); - break; - case 'clear': - _historyController.baseCtr - .onClearHistory(context, () { - _historyController.loadingState.value = - const Success(null); - if (_historyController.tabController != - null) { - for (final item - in _historyController.tabs) { - try { - Get.find( - tag: item.type) - .loadingState - .value = const Success(null); - } catch (_) {} - } - } - }); - break; - case 'del': - currCtr().onDelHistory(); - break; - case 'multiple': - _historyController - .baseCtr.enableMultiSelect.value = true; - break; - } - }, - itemBuilder: (BuildContext context) => - >[ - PopupMenuItem( - value: 'pause', - child: Obx( - () => Text( - !_historyController - .baseCtr.pauseStatus.value - ? '暂停观看记录' - : '恢复观看记录', - ), - ), - ), - const PopupMenuItem( - value: 'clear', - child: Text('清空观看记录'), - ), - const PopupMenuItem( - value: 'del', - child: Text('删除已看记录'), - ), - const PopupMenuItem( - value: 'multiple', - child: Text('多选删除'), - ), - ], - ), - const SizedBox(width: 6), - ], - ), - child2: AppBar( - leading: IconButton( - tooltip: '取消', - onPressed: currCtr().handleSelect, - icon: const Icon(Icons.close_outlined), - ), - title: Obx( - () => Text( - '已选: ${_historyController.baseCtr.checkedCount.value}', - ), - ), - actions: [ - TextButton( - onPressed: () => currCtr().handleSelect(true), - child: const Text('全选'), - ), - TextButton( - onPressed: () => - currCtr().onDelCheckedHistory(context), - child: Text( - '删除', - style: TextStyle( - color: Theme.of(context).colorScheme.error), + () { + final enableMultiSelect = + _historyController.baseCtr.enableMultiSelect.value; + return PopScope( + canPop: !enableMultiSelect, + onPopInvokedWithResult: (didPop, result) { + if (enableMultiSelect) { + currCtr().handleSelect(); + } + }, + child: Scaffold( + appBar: widget.type != null + ? null + : AppBarWidget( + visible: enableMultiSelect, + child1: AppBar( + title: const Text('观看记录'), + actions: [ + IconButton( + tooltip: '搜索', + onPressed: () => Get.toNamed('/historySearch'), + icon: const Icon(Icons.search_outlined), ), - ), - const SizedBox(width: 6), - ], - ), - ), - body: Obx( - () => _historyController.tabs.isNotEmpty - ? SafeArea( - top: false, - bottom: false, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TabBar( - controller: _historyController.tabController, - onTap: (index) { - if (!_historyController - .tabController!.indexIsChanging) { - currCtr().scrollController.animToTop(); - } else { - if (enableMultiSelect) { - currCtr(_historyController - .tabController!.previousIndex) - .handleSelect(); - } + PopupMenuButton( + onSelected: (String type) { + // 处理菜单项选择的逻辑 + switch (type) { + case 'pause': + _historyController.baseCtr + .onPauseHistory(context); + break; + case 'clear': + _historyController.baseCtr + .onClearHistory(context, () { + _historyController.loadingState.value = + const Success(null); + if (_historyController.tabController != + null) { + for (final item + in _historyController.tabs) { + try { + Get.find( + tag: item.type) + .loadingState + .value = const Success(null); + } catch (_) {} + } + } + }); + break; + case 'del': + currCtr().onDelHistory(); + break; + case 'multiple': + _historyController.baseCtr + .enableMultiSelect.value = true; + break; } }, - tabs: [ - const Tab(text: '全部'), - ..._historyController.tabs.map( - (item) => Tab(text: item.name), + itemBuilder: (BuildContext context) => + >[ + PopupMenuItem( + value: 'pause', + child: Obx( + () => Text( + !_historyController + .baseCtr.pauseStatus.value + ? '暂停观看记录' + : '恢复观看记录', + ), + ), + ), + const PopupMenuItem( + value: 'clear', + child: Text('清空观看记录'), + ), + const PopupMenuItem( + value: 'del', + child: Text('删除已看记录'), + ), + const PopupMenuItem( + value: 'multiple', + child: Text('多选删除'), ), ], ), - Expanded( - child: TabBarView( - physics: enableMultiSelect - ? const NeverScrollableScrollPhysics() - : const CustomTabBarViewScrollPhysics(), + const SizedBox(width: 6), + ], + ), + child2: AppBar( + leading: IconButton( + tooltip: '取消', + onPressed: currCtr().handleSelect, + icon: const Icon(Icons.close_outlined), + ), + title: Obx( + () => Text( + '已选: ${_historyController.baseCtr.checkedCount.value}', + ), + ), + actions: [ + TextButton( + onPressed: () => currCtr().handleSelect(true), + child: const Text('全选'), + ), + TextButton( + onPressed: () => + currCtr().onDelCheckedHistory(context), + child: Text( + '删除', + style: TextStyle( + color: + Theme.of(context).colorScheme.error), + ), + ), + const SizedBox(width: 6), + ], + ), + ), + body: Obx( + () => _historyController.tabs.isNotEmpty + ? SafeArea( + top: false, + bottom: false, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TabBar( controller: _historyController.tabController, - children: [ - KeepAliveWrapper( - builder: (context) => _buildPage), + onTap: (index) { + if (!_historyController + .tabController!.indexIsChanging) { + currCtr().scrollController.animToTop(); + } else { + if (enableMultiSelect) { + currCtr(_historyController + .tabController!.previousIndex) + .handleSelect(); + } + } + }, + tabs: [ + const Tab(text: '全部'), ..._historyController.tabs.map( - (item) => HistoryPage(type: item.type), + (item) => Tab(text: item.name), ), ], ), - ), - ], + Expanded( + child: TabBarView( + physics: enableMultiSelect + ? const NeverScrollableScrollPhysics() + : const CustomTabBarViewScrollPhysics(), + controller: + _historyController.tabController, + children: [ + KeepAliveWrapper( + builder: (context) => _buildPage), + ..._historyController.tabs.map( + (item) => HistoryPage(type: item.type), + ), + ], + ), + ), + ], + ), + ) + : SafeArea( + top: false, + bottom: false, + child: _buildPage, ), - ) - : SafeArea( - top: false, - bottom: false, - child: _buildPage, - ), + ), ), - ), - ), + ); + }, ); } diff --git a/lib/pages/home/view.dart b/lib/pages/home/view.dart index 873d645d2..725334507 100644 --- a/lib/pages/home/view.dart +++ b/lib/pages/home/view.dart @@ -253,17 +253,18 @@ Widget msgBadge(MainController mainController) { Get.toNamed('/whisper'); } + final msgUnReadCount = mainController.msgUnReadCount.value; return GestureDetector( onTap: toWhisper, child: Badge( isLabelVisible: mainController.msgBadgeMode != DynamicBadgeMode.hidden && - mainController.msgUnReadCount.value.isNotEmpty, + msgUnReadCount.isNotEmpty, alignment: mainController.msgBadgeMode == DynamicBadgeMode.number ? const Alignment(0, -0.5) : const Alignment(0.5, -0.5), label: mainController.msgBadgeMode == DynamicBadgeMode.number && - mainController.msgUnReadCount.value.isNotEmpty - ? Text(mainController.msgUnReadCount.value.toString()) + msgUnReadCount.isNotEmpty + ? Text(msgUnReadCount) : null, child: IconButton( tooltip: '消息', diff --git a/lib/pages/later/child_view.dart b/lib/pages/later/child_view.dart index 73c079c86..943cd75ec 100644 --- a/lib/pages/later/child_view.dart +++ b/lib/pages/later/child_view.dart @@ -77,6 +77,8 @@ class _LaterViewChildPageState extends State _laterController.onLoadMore(); } var videoItem = response[index]; + final enableMultiSelect = + _laterController.baseCtr.enableMultiSelect.value; return Stack( clipBehavior: Clip.none, children: [ @@ -99,12 +101,11 @@ class _LaterViewChildPageState extends State }, ); }, - onTap: !_laterController.baseCtr.enableMultiSelect.value + onTap: !enableMultiSelect ? null : () => _laterController.onSelect(videoItem), onLongPress: () { - if (!_laterController - .baseCtr.enableMultiSelect.value) { + if (!enableMultiSelect) { _laterController.baseCtr.enableMultiSelect.value = true; _laterController.onSelect(videoItem); diff --git a/lib/pages/later/view.dart b/lib/pages/later/view.dart index 23f2ce7d0..5c1c85545 100644 --- a/lib/pages/later/view.dart +++ b/lib/pages/later/view.dart @@ -58,73 +58,78 @@ class _LaterPageState extends State @override Widget build(BuildContext context) { return Obx( - () => PopScope( - canPop: !_baseCtr.enableMultiSelect.value, - onPopInvokedWithResult: (didPop, result) { - if (_baseCtr.enableMultiSelect.value) { - currCtr().handleSelect(); - } - }, - child: Scaffold( - resizeToAvoidBottomInset: false, - appBar: _buildAppbar, - floatingActionButton: Obx( - () => currCtr().loadingState.value.isSuccess - ? FloatingActionButton.extended( - onPressed: currCtr().toViewPlayAll, - label: const Text('播放全部'), - icon: const Icon(Icons.playlist_play), - ) - : const SizedBox.shrink(), - ), - body: SafeArea( - top: false, - bottom: false, - child: Column( - children: [ - TabBar( - // isScrollable: true, - // tabAlignment: TabAlignment.start, - controller: _tabController, - tabs: LaterViewType.values.map((item) { - final count = _baseCtr.counts[item]; - return Tab( - text: '${item.title}${count != -1 ? '($count)' : ''}'); - }).toList(), - onTap: (_) { - if (!_tabController.indexIsChanging) { - currCtr().scrollController.animToTop(); - } else { - if (_baseCtr.enableMultiSelect.value) { - currCtr(_tabController.previousIndex).handleSelect(); - } - } - }, - ), - Expanded( - child: TabBarView( - physics: _baseCtr.enableMultiSelect.value - ? const NeverScrollableScrollPhysics() - : const CustomTabBarViewScrollPhysics(), + () { + final enableMultiSelect = _baseCtr.enableMultiSelect.value; + return PopScope( + canPop: !enableMultiSelect, + onPopInvokedWithResult: (didPop, result) { + if (enableMultiSelect) { + currCtr().handleSelect(); + } + }, + child: Scaffold( + resizeToAvoidBottomInset: false, + appBar: _buildAppbar(enableMultiSelect), + floatingActionButton: Obx( + () => currCtr().loadingState.value.isSuccess + ? FloatingActionButton.extended( + onPressed: currCtr().toViewPlayAll, + label: const Text('播放全部'), + icon: const Icon(Icons.playlist_play), + ) + : const SizedBox.shrink(), + ), + body: SafeArea( + top: false, + bottom: false, + child: Column( + children: [ + TabBar( + // isScrollable: true, + // tabAlignment: TabAlignment.start, controller: _tabController, - children: - LaterViewType.values.map((item) => item.page).toList(), + tabs: LaterViewType.values.map((item) { + final count = _baseCtr.counts[item]; + return Tab( + text: + '${item.title}${count != -1 ? '($count)' : ''}'); + }).toList(), + onTap: (_) { + if (!_tabController.indexIsChanging) { + currCtr().scrollController.animToTop(); + } else { + if (enableMultiSelect) { + currCtr(_tabController.previousIndex).handleSelect(); + } + } + }, ), - ), - ], + Expanded( + child: TabBarView( + physics: enableMultiSelect + ? const NeverScrollableScrollPhysics() + : const CustomTabBarViewScrollPhysics(), + controller: _tabController, + children: LaterViewType.values + .map((item) => item.page) + .toList(), + ), + ), + ], + ), ), ), - ), - ), + ); + }, ); } - PreferredSizeWidget get _buildAppbar { + PreferredSizeWidget _buildAppbar(bool enableMultiSelect) { final theme = Theme.of(context); Color color = theme.colorScheme.secondary; return AppBarWidget( - visible: _baseCtr.enableMultiSelect.value, + visible: enableMultiSelect, child1: AppBar( title: const Text('稍后再看'), actions: [ @@ -248,11 +253,7 @@ class _LaterPageState extends State onPressed: currCtr().handleSelect, icon: const Icon(Icons.close_outlined), ), - title: Obx( - () => Text( - '已选: ${_baseCtr.checkedCount.value}', - ), - ), + title: Obx(() => Text('已选: ${_baseCtr.checkedCount.value}')), actions: [ TextButton( style: TextButton.styleFrom( diff --git a/lib/pages/live/view.dart b/lib/pages/live/view.dart index 8ac0a1cd3..27f2a1ff4 100644 --- a/lib/pages/live/view.dart +++ b/lib/pages/live/view.dart @@ -83,26 +83,29 @@ class _LivePageState extends CommonPageState late final item = data .second!.cardData!.areaEntranceV3!.list![index - 1]; return Obx( - () => SearchText( - fontSize: 14, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 3, - ), - text: index == 0 ? '推荐' : '${item.title}', - bgColor: index == controller.areaIndex.value - ? theme.colorScheme.secondaryContainer - : Colors.transparent, - textColor: index == controller.areaIndex.value - ? theme.colorScheme.onSecondaryContainer - : null, - onTap: (value) { - controller.onSelectArea( - index, - index == 0 ? null : item, - ); - }, - ), + () { + final isCurr = index == controller.areaIndex.value; + return SearchText( + fontSize: 14, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + text: index == 0 ? '推荐' : '${item.title}', + bgColor: isCurr + ? theme.colorScheme.secondaryContainer + : Colors.transparent, + textColor: isCurr + ? theme.colorScheme.onSecondaryContainer + : null, + onTap: (value) { + controller.onSelectArea( + index, + index == 0 ? null : item, + ); + }, + ); + }, ); }, itemCount: @@ -153,26 +156,29 @@ class _LivePageState extends CommonPageState childBuilder: (index) { late final item = controller.newTags![index]; return Obx( - () => SearchText( - fontSize: 13, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 3, - ), - text: '${item.name}', - bgColor: index == controller.tagIndex.value - ? theme.colorScheme.secondaryContainer - : Colors.transparent, - textColor: index == controller.tagIndex.value - ? theme.colorScheme.onSecondaryContainer - : null, - onTap: (value) { - controller.onSelectTag( - index, - item.sortType, - ); - }, - ), + () { + final isCurr = index == controller.tagIndex.value; + return SearchText( + fontSize: 13, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + text: '${item.name}', + bgColor: isCurr + ? theme.colorScheme.secondaryContainer + : Colors.transparent, + textColor: isCurr + ? theme.colorScheme.onSecondaryContainer + : null, + onTap: (value) { + controller.onSelectTag( + index, + item.sortType, + ); + }, + ); + }, ); }, itemCount: controller.newTags!.length, diff --git a/lib/pages/live_area_detail/child/view.dart b/lib/pages/live_area_detail/child/view.dart index cdd6ced47..7e45ad02a 100644 --- a/lib/pages/live_area_detail/child/view.dart +++ b/lib/pages/live_area_detail/child/view.dart @@ -87,26 +87,29 @@ class _LiveAreaChildPageState extends State childBuilder: (index) { late final item = _controller.newTags![index]; return Obx( - () => SearchText( - fontSize: 14, - padding: const EdgeInsets.symmetric( - horizontal: 8, - vertical: 3, - ), - text: '${item.name}', - bgColor: index == _controller.tagIndex.value - ? theme.colorScheme.secondaryContainer - : Colors.transparent, - textColor: index == _controller.tagIndex.value - ? theme.colorScheme.onSecondaryContainer - : null, - onTap: (value) { - _controller.onSelectTag( - index, - item.sortType, - ); - }, - ), + () { + final isCurr = index == _controller.tagIndex.value; + return SearchText( + fontSize: 14, + padding: const EdgeInsets.symmetric( + horizontal: 8, + vertical: 3, + ), + text: '${item.name}', + bgColor: isCurr + ? theme.colorScheme.secondaryContainer + : Colors.transparent, + textColor: isCurr + ? theme.colorScheme.onSecondaryContainer + : null, + onTap: (value) { + _controller.onSelectTag( + index, + item.sortType, + ); + }, + ); + }, ); }, itemCount: _controller.newTags!.length, diff --git a/lib/pages/live_dm_block/view.dart b/lib/pages/live_dm_block/view.dart index fe0c396b8..cbafe804e 100644 --- a/lib/pages/live_dm_block/view.dart +++ b/lib/pages/live_dm_block/view.dart @@ -187,23 +187,27 @@ class _LiveDmBlockPageState extends State { return [ const SizedBox(height: 6), Obx( - () => Row( - spacing: 10, - children: [ - Text('屏蔽${_controller.isEnable.value ? '已' : '未'}开启'), - Transform.scale( - scale: .8, - child: Switch( - value: _controller.isEnable.value, - onChanged: _controller.setEnable, + () { + final isEnable = _controller.isEnable.value; + return Row( + spacing: 10, + children: [ + Text('屏蔽${isEnable ? '已' : '未'}开启'), + Transform.scale( + scale: .8, + child: Switch( + value: isEnable, + onChanged: _controller.setEnable, + ), ), - ), - ], - ), + ], + ); + }, ), const SizedBox(height: 6), Obx( () { + final level = _controller.level.value; return Row( children: [ const Text('用户等级'), @@ -214,23 +218,22 @@ class _LiveDmBlockPageState extends State { year2023: true, inactiveColor: theme.colorScheme.onInverseSurface, padding: const EdgeInsets.only(left: 20, right: 25), - value: _controller.level.value.toDouble(), - onChangeStart: (value) => - _controller.oldLevel = _controller.level.value, + value: level.toDouble(), + onChangeStart: (value) => _controller.oldLevel = level, onChanged: (value) => _controller.level.value = value.round().clamp(0, 60), onChangeEnd: (value) { - if (_controller.oldLevel != _controller.level.value) { + if (_controller.oldLevel != level) { _controller.setSilent( LiveDmSilentType.level, - _controller.level.value, + level, onError: () => _controller.level.value = _controller.oldLevel ?? 0, ); } }, ), - Text('${_controller.level.value} 以下') + Text('$level 以下') ], ); }, diff --git a/lib/pages/live_follow/controller.dart b/lib/pages/live_follow/controller.dart index 61785524a..7fe52762c 100644 --- a/lib/pages/live_follow/controller.dart +++ b/lib/pages/live_follow/controller.dart @@ -17,7 +17,8 @@ class LiveFollowController @override void checkIsEnd(int length) { - if (count.value != null && length >= count.value!) { + final count = this.count.value; + if (count != null && length >= count) { isEnd = true; } } diff --git a/lib/pages/live_follow/view.dart b/lib/pages/live_follow/view.dart index 8236de481..e2cb09c6b 100644 --- a/lib/pages/live_follow/view.dart +++ b/lib/pages/live_follow/view.dart @@ -25,9 +25,10 @@ class _LiveFollowPageState extends State { return Scaffold( appBar: AppBar( title: Obx( - () => Text(_controller.count.value != null - ? '${_controller.count.value}人正在直播' - : '关注直播'), + () { + final count = _controller.count.value; + return Text(count != null ? '$count人正在直播' : '关注直播'); + }, ), ), body: SafeArea( diff --git a/lib/pages/live_room/controller.dart b/lib/pages/live_room/controller.dart index 3f2ef4fdf..0f6e3dbb1 100644 --- a/lib/pages/live_room/controller.dart +++ b/lib/pages/live_room/controller.dart @@ -133,9 +133,10 @@ class LiveRoomController extends GetxController { Future queryLiveInfoH5() async { var res = await LiveHttp.liveRoomInfoH5(roomId: roomId); if (res['status']) { - roomInfoH5.value = res['data']; + RoomInfoH5Data data = res['data']; + roomInfoH5.value = data; videoPlayerServiceHandler.onVideoDetailChange( - roomInfoH5.value, + data, roomId, heroTag, ); diff --git a/lib/pages/live_room/view.dart b/lib/pages/live_room/view.dart index ae8829613..b6a8d2292 100644 --- a/lib/pages/live_room/view.dart +++ b/lib/pages/live_room/view.dart @@ -244,27 +244,29 @@ class _LiveRoomPageState extends State clipBehavior: Clip.none, children: [ Obx( - () => isFullScreen - ? const SizedBox.shrink() - : Positioned.fill( - child: Opacity( - opacity: 0.6, - child: _liveRoomController.roomInfoH5.value?.roomInfo - ?.appBackground?.isNotEmpty == - true - ? CachedNetworkImage( - fit: BoxFit.cover, - width: Get.width, - height: Get.height, - imageUrl: _liveRoomController.roomInfoH5.value! - .roomInfo!.appBackground!.http2https, - ) - : Image.asset( - 'assets/images/live/default_bg.webp', - fit: BoxFit.cover, - ), - ), - ), + () { + if (isFullScreen) { + return const SizedBox.shrink(); + } + final appBackground = _liveRoomController + .roomInfoH5.value?.roomInfo?.appBackground; + return Positioned.fill( + child: Opacity( + opacity: 0.6, + child: appBackground?.isNotEmpty == true + ? CachedNetworkImage( + fit: BoxFit.cover, + width: Get.width, + height: Get.height, + imageUrl: appBackground!.http2https, + ) + : Image.asset( + 'assets/images/live/default_bg.webp', + fit: BoxFit.cover, + ), + ), + ); + }, ), SafeArea( top: !isFullScreen, @@ -564,20 +566,24 @@ class _LiveRoomPageState extends State child: Row( children: [ Obx( - () => IconButton( - onPressed: () { - plPlayerController.enableShowDanmaku.value = - !plPlayerController.enableShowDanmaku.value; - GStorage.setting.put(SettingBoxKey.enableShowDanmaku, - plPlayerController.enableShowDanmaku.value); - }, - icon: Icon( - plPlayerController.enableShowDanmaku.value - ? Icons.subtitles_outlined - : Icons.subtitles_off_outlined, - color: _color, - ), - ), + () { + final enableShowDanmaku = + plPlayerController.enableShowDanmaku.value; + return IconButton( + onPressed: () { + final newVal = !enableShowDanmaku; + plPlayerController.enableShowDanmaku.value = newVal; + GStorage.setting + .put(SettingBoxKey.enableShowDanmaku, newVal); + }, + icon: Icon( + enableShowDanmaku + ? Icons.subtitles_outlined + : Icons.subtitles_off_outlined, + color: _color, + ), + ); + }, ), Expanded( child: Text( diff --git a/lib/pages/live_room/widgets/bottom_control.dart b/lib/pages/live_room/widgets/bottom_control.dart index 3a07ebbd5..5f740c53a 100644 --- a/lib/pages/live_room/widgets/bottom_control.dart +++ b/lib/pages/live_room/widgets/bottom_control.dart @@ -77,29 +77,33 @@ class BottomControl extends StatelessWidget { ), const SizedBox(width: 10), Obx( - () => SizedBox( - width: 35, - height: 35, - child: IconButton( - tooltip: '弹幕开关', - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), + () { + final enableShowDanmaku = + plPlayerController.enableShowDanmaku.value; + return SizedBox( + width: 35, + height: 35, + child: IconButton( + tooltip: '弹幕开关', + style: ButtonStyle( + padding: WidgetStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + final newVal = !enableShowDanmaku; + plPlayerController.enableShowDanmaku.value = newVal; + GStorage.setting + .put(SettingBoxKey.enableShowDanmaku, newVal); + }, + icon: Icon( + size: 18, + enableShowDanmaku + ? Icons.subtitles_outlined + : Icons.subtitles_off_outlined, + color: Colors.white, + ), ), - onPressed: () { - plPlayerController.enableShowDanmaku.value = - !plPlayerController.enableShowDanmaku.value; - GStorage.setting.put(SettingBoxKey.enableShowDanmaku, - plPlayerController.enableShowDanmaku.value); - }, - icon: Icon( - size: 18, - plPlayerController.enableShowDanmaku.value - ? Icons.subtitles_outlined - : Icons.subtitles_off_outlined, - color: Colors.white, - ), - ), - ), + ); + }, ), Obx( () => Container( diff --git a/lib/pages/live_room/widgets/header_control.dart b/lib/pages/live_room/widgets/header_control.dart index d077bc9e8..b4fb49f14 100644 --- a/lib/pages/live_room/widgets/header_control.dart +++ b/lib/pages/live_room/widgets/header_control.dart @@ -26,6 +26,7 @@ class LiveHeaderControl extends StatelessWidget { @override Widget build(BuildContext context) { + final isFullScreen = plPlayerController.isFullScreen.value; return AppBar( backgroundColor: Colors.transparent, foregroundColor: Colors.white, @@ -35,7 +36,7 @@ class LiveHeaderControl extends StatelessWidget { title: Row( spacing: 10, children: [ - if (plPlayerController.isFullScreen.value) + if (isFullScreen) SizedBox( width: 35, height: 35, @@ -64,7 +65,7 @@ class LiveHeaderControl extends StatelessWidget { style: const TextStyle( fontSize: 15, height: 1, color: Colors.white), ), - if (plPlayerController.isFullScreen.value && upName != null) + if (isFullScreen && upName != null) Text( upName!, maxLines: 1, @@ -93,31 +94,33 @@ class LiveHeaderControl extends StatelessWidget { ), ), Obx( - () => SizedBox( - width: 35, - height: 35, - child: IconButton( - onPressed: () { - plPlayerController.onlyPlayAudio.value = - !plPlayerController.onlyPlayAudio.value; - onPlayAudio(); - }, - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), + () { + final onlyPlayAudio = plPlayerController.onlyPlayAudio.value; + return SizedBox( + width: 35, + height: 35, + child: IconButton( + onPressed: () { + plPlayerController.onlyPlayAudio.value = !onlyPlayAudio; + onPlayAudio(); + }, + style: ButtonStyle( + padding: WidgetStateProperty.all(EdgeInsets.zero), + ), + icon: onlyPlayAudio + ? const Icon( + size: 18, + MdiIcons.musicCircle, + color: Colors.white, + ) + : const Icon( + size: 18, + MdiIcons.musicCircleOutline, + color: Colors.white, + ), ), - icon: plPlayerController.onlyPlayAudio.value - ? const Icon( - size: 18, - MdiIcons.musicCircle, - color: Colors.white, - ) - : const Icon( - size: 18, - MdiIcons.musicCircleOutline, - color: Colors.white, - ), - ), - ), + ); + }, ), if (Platform.isAndroid) SizedBox( diff --git a/lib/pages/main/view.dart b/lib/pages/main/view.dart index 84f1036ee..885c7d835 100644 --- a/lib/pages/main/view.dart +++ b/lib/pages/main/view.dart @@ -368,14 +368,18 @@ class _MainAppState extends State final icon = selected ? type.selectIcon : type.icon; return type == NavigationBarType.dynamics ? Obx( - () => Badge( - isLabelVisible: _mainController.dynCount.value > 0, - label: _mainController.dynamicBadgeMode == DynamicBadgeMode.number - ? Text(_mainController.dynCount.value.toString()) - : null, - padding: const EdgeInsets.symmetric(horizontal: 6), - child: icon, - ), + () { + final dynCount = _mainController.dynCount.value; + return Badge( + isLabelVisible: dynCount > 0, + label: + _mainController.dynamicBadgeMode == DynamicBadgeMode.number + ? Text(dynCount.toString()) + : null, + padding: const EdgeInsets.symmetric(horizontal: 6), + child: icon, + ); + }, ) : icon; } diff --git a/lib/pages/match_info/view.dart b/lib/pages/match_info/view.dart index e4adc4d8a..bb3b63b35 100644 --- a/lib/pages/match_info/view.dart +++ b/lib/pages/match_info/view.dart @@ -273,17 +273,20 @@ class _MatchInfoPageState extends State { child: Row( children: [ Obx( - () => AnimatedSwitcher( - duration: const Duration(milliseconds: 400), - transitionBuilder: - (Widget child, Animation animation) { - return ScaleTransition(scale: animation, child: child); - }, - child: Text( - '${_controller.count.value == -1 ? 0 : NumUtil.numFormat(_controller.count.value)}条回复', - key: ValueKey(_controller.count.value), - ), - ), + () { + final count = _controller.count.value; + return AnimatedSwitcher( + duration: const Duration(milliseconds: 400), + transitionBuilder: + (Widget child, Animation animation) { + return ScaleTransition(scale: animation, child: child); + }, + child: Text( + '${count == -1 ? 0 : NumUtil.numFormat(count)}条回复', + key: ValueKey(count), + ), + ); + }, ), const Spacer(), SizedBox( diff --git a/lib/pages/media/view.dart b/lib/pages/media/view.dart index 133c991d6..0ad6fe519 100644 --- a/lib/pages/media/view.dart +++ b/lib/pages/media/view.dart @@ -119,33 +119,36 @@ class _MediaPageState extends CommonPageState title: Padding( padding: const EdgeInsets.only(left: 10), child: Obx( - () => Text.rich( - TextSpan( - children: [ - TextSpan( - text: '我的收藏 ', - style: TextStyle( - fontSize: theme.textTheme.titleMedium!.fontSize, - fontWeight: FontWeight.bold), - ), - if (controller.count.value != -1) + () { + final count = controller.count.value; + return Text.rich( + TextSpan( + children: [ TextSpan( - text: "${controller.count.value} ", + text: '我的收藏 ', style: TextStyle( - fontSize: theme.textTheme.titleSmall!.fontSize, + fontSize: theme.textTheme.titleMedium!.fontSize, + fontWeight: FontWeight.bold), + ), + if (count != -1) + TextSpan( + text: "$count ", + style: TextStyle( + fontSize: theme.textTheme.titleSmall!.fontSize, + color: theme.colorScheme.primary, + ), + ), + WidgetSpan( + child: Icon( + Icons.arrow_forward_ios, + size: 18, color: theme.colorScheme.primary, ), ), - WidgetSpan( - child: Icon( - Icons.arrow_forward_ios, - size: 18, - color: theme.colorScheme.primary, - ), - ), - ], - ), - ), + ], + ), + ); + }, ), ), trailing: IconButton( diff --git a/lib/pages/member/controller.dart b/lib/pages/member/controller.dart index cb7641fa6..cac35ba30 100644 --- a/lib/pages/member/controller.dart +++ b/lib/pages/member/controller.dart @@ -188,13 +188,14 @@ class MemberController extends CommonDataController } Future _onBlock() async { + final isBlocked = relation.value == 128; var res = await VideoHttp.relationMod( mid: mid, - act: relation.value != 128 ? 5 : 6, + act: isBlocked ? 6 : 5, reSrc: 11, ); if (res['status']) { - relation.value = relation.value != 128 ? 128 : 0; + relation.value = isBlocked ? 0 : 128; } } @@ -212,9 +213,7 @@ class MemberController extends CommonDataController context: context, mid: mid, isFollow: isFollow, - callback: (attribute) { - relation.value = attribute; - }, + callback: (attribute) => relation.value = attribute, ); } } diff --git a/lib/pages/member_opus/view.dart b/lib/pages/member_opus/view.dart index e5ef2009b..e48b7c60d 100644 --- a/lib/pages/member_opus/view.dart +++ b/lib/pages/member_opus/view.dart @@ -103,8 +103,10 @@ class _MemberOpusState extends State ), icon: const Icon(size: 20, Icons.sort), label: Obx( - () => Text(_controller.type.value.text ?? - _controller.type.value.tabName!), + () { + final type = _controller.type.value; + return Text(type.text ?? type.tabName!); + }, ), ), ), diff --git a/lib/pages/member_upower_rank/view.dart b/lib/pages/member_upower_rank/view.dart index ccbebf099..113d90d84 100644 --- a/lib/pages/member_upower_rank/view.dart +++ b/lib/pages/member_upower_rank/view.dart @@ -66,10 +66,13 @@ class _UpowerRankPageState extends State if (widget.privilegeType == null) { return Scaffold( appBar: AppBar( - title: Obx(() => _controller.name.value == null - ? const SizedBox.shrink() - : Text( - '${_controller.name.value} 充电排行榜${_controller.memberTotal == 0 ? '' : '(${_controller.memberTotal})'}')), + title: Obx(() { + final name = _controller.name.value; + return name == null + ? const SizedBox.shrink() + : Text( + '$name 充电排行榜${_controller.memberTotal == 0 ? '' : '(${_controller.memberTotal})'}'); + }), ), body: SafeArea( top: false, @@ -78,58 +81,62 @@ class _UpowerRankPageState extends State child: ConstrainedBox( constraints: const BoxConstraints(maxWidth: 625), child: Obx( - () => _controller.tabs.value != null - ? DefaultTabController( - length: _controller.tabs.value!.length, - child: Builder( - builder: (context) { - return Column( - children: [ - TabBar( - isScrollable: true, - tabAlignment: TabAlignment.start, - tabs: _controller.tabs.value! - .map((e) => Tab( - text: - '${e.name!}(${e.memberTotal ?? 0})')) - .toList(), - onTap: (index) { - if (!DefaultTabController.of(context) - .indexIsChanging) { - try { - if (index == 0) { - _controller.animateToTop(); - } else { - Get.find( - tag: - '$_tag${_controller.tabs.value![index].privilegeType}') - .animateToTop(); - } - } catch (_) {} - } - }, - ), - Expanded( - child: tabBarView( - children: [ - KeepAliveWrapper( - builder: (context) => child), - ..._controller.tabs.value! - .sublist(1) - .map((e) => UpowerRankPage( - upMid: _upMid, - tag: _tag, - privilegeType: e.privilegeType, - )) - ], + () { + final tabs = _controller.tabs.value; + return tabs != null + ? DefaultTabController( + length: tabs.length, + child: Builder( + builder: (context) { + return Column( + children: [ + TabBar( + isScrollable: true, + tabAlignment: TabAlignment.start, + tabs: tabs + .map((e) => Tab( + text: + '${e.name!}(${e.memberTotal ?? 0})')) + .toList(), + onTap: (index) { + if (!DefaultTabController.of(context) + .indexIsChanging) { + try { + if (index == 0) { + _controller.animateToTop(); + } else { + Get.find( + tag: + '$_tag${tabs[index].privilegeType}') + .animateToTop(); + } + } catch (_) {} + } + }, ), - ), - ], - ); - }, - ), - ) - : child, + Expanded( + child: tabBarView( + children: [ + KeepAliveWrapper( + builder: (context) => child), + ...tabs + .sublist(1) + .map((e) => UpowerRankPage( + upMid: _upMid, + tag: _tag, + privilegeType: + e.privilegeType, + )) + ], + ), + ), + ], + ); + }, + ), + ) + : child; + }, ), ), ), diff --git a/lib/pages/member_video/controller.dart b/lib/pages/member_video/controller.dart index ac4532787..547eef5af 100644 --- a/lib/pages/member_video/controller.dart +++ b/lib/pages/member_video/controller.dart @@ -141,9 +141,10 @@ class MemberVideoCtr } Future toViewPlayAll() async { - if (episodicButton.value.text == '继续播放' && - episodicButton.value.uri?.isNotEmpty == true) { - final params = Uri.parse(episodicButton.value.uri!).queryParameters; + final episodicButton = this.episodicButton.value; + if (episodicButton.text == '继续播放' && + episodicButton.uri?.isNotEmpty == true) { + final params = Uri.parse(episodicButton.uri!).queryParameters; String? oid = params['oid']; if (oid != null) { var bvid = IdUtils.av2bv(int.parse(oid)); @@ -155,8 +156,7 @@ class MemberVideoCtr 'sourceType': 'archive', 'mediaId': seasonId ?? seriesId ?? mid, 'oid': oid, - 'favTitle': - '$username: ${title ?? episodicButton.value.text ?? '播放全部'}', + 'favTitle': '$username: ${title ?? episodicButton.text ?? '播放全部'}', if (seriesId == null) 'count': count.value, if (seasonId != null || seriesId != null) 'mediaType': params['page_type'], @@ -197,11 +197,11 @@ class MemberVideoCtr 'mediaId': seasonId ?? seriesId ?? mid, 'oid': IdUtils.bv2av(element.bvid!), 'favTitle': - '$username: ${title ?? episodicButton.value.text ?? '播放全部'}', + '$username: ${title ?? episodicButton.text ?? '播放全部'}', if (seriesId == null) 'count': count.value, if (seasonId != null || seriesId != null) - 'mediaType': Uri.parse(episodicButton.value.uri!) - .queryParameters['page_type'], + 'mediaType': + Uri.parse(episodicButton.uri!).queryParameters['page_type'], 'desc': desc, if (type == ContributeType.video) 'sortField': order.value == 'click' ? 2 : 1, diff --git a/lib/pages/member_video/view.dart b/lib/pages/member_video/view.dart index 850331cf9..a2b0fef76 100644 --- a/lib/pages/member_video/view.dart +++ b/lib/pages/member_video/view.dart @@ -134,43 +134,47 @@ class _MemberVideoState extends State child: Row( children: [ const SizedBox(width: 8), - Obx( - () => Padding( - padding: const EdgeInsets.only(left: 6), - child: Text( - _controller.count.value != -1 - ? '共${_controller.count.value}视频' - : '', - style: const TextStyle(fontSize: 13), - ), + Padding( + padding: const EdgeInsets.only(left: 6), + child: Obx( + () { + final count = _controller.count.value; + return Text( + count != -1 ? '共$count视频' : '', + style: const TextStyle(fontSize: 13), + ); + }, ), ), Obx( - () => _controller.episodicButton.value.uri != null - ? Container( - height: 35, - padding: EdgeInsets.only( - left: _controller.count.value != -1 - ? 6 - : 0), - child: TextButton.icon( - onPressed: _controller.toViewPlayAll, - icon: Icon( - Icons.play_circle_outline_rounded, - size: 16, - color: theme.colorScheme.secondary, - ), - label: Text( - _controller.episodicButton.value.text ?? - '播放全部', - style: TextStyle( - fontSize: 13, + () { + final episodicButton = + _controller.episodicButton.value; + return episodicButton.uri?.isNotEmpty == true + ? Container( + height: 35, + padding: EdgeInsets.only( + left: _controller.count.value != -1 + ? 6 + : 0), + child: TextButton.icon( + onPressed: _controller.toViewPlayAll, + icon: Icon( + Icons.play_circle_outline_rounded, + size: 16, color: theme.colorScheme.secondary, ), + label: Text( + episodicButton.text ?? '播放全部', + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.secondary, + ), + ), ), - ), - ) - : const SizedBox.shrink(), + ) + : const SizedBox.shrink(); + }, ), const Spacer(), SizedBox( diff --git a/lib/pages/mine/controller.dart b/lib/pages/mine/controller.dart index 2d9a14cb1..144dd6433 100644 --- a/lib/pages/mine/controller.dart +++ b/lib/pages/mine/controller.dart @@ -88,8 +88,9 @@ class MineController extends GetxController { SmartDialog.showToast('请先登录'); return; } - anonymity.value = !anonymity.value; - if (anonymity.value) { + final newVal = !anonymity.value; + anonymity.value = newVal; + if (newVal) { SmartDialog.dismiss(); SmartDialog.show( clickMaskDismiss: false, @@ -195,12 +196,13 @@ class MineController extends GetxController { } void onChangeTheme() { - themeType.value = nextThemeType; + final newVal = nextThemeType; + themeType.value = newVal; try { - Get.find().themeType.value = themeType.value; + Get.find().themeType.value = newVal; } catch (_) {} - GStorage.setting.put(SettingBoxKey.themeMode, themeType.value.index); - Get.changeThemeMode(themeType.value.toThemeMode); + GStorage.setting.put(SettingBoxKey.themeMode, newVal.index); + Get.changeThemeMode(newVal.toThemeMode); } void pushFollow() { diff --git a/lib/pages/mine/view.dart b/lib/pages/mine/view.dart index 9469cab50..cd421b7eb 100644 --- a/lib/pages/mine/view.dart +++ b/lib/pages/mine/view.dart @@ -34,15 +34,16 @@ class _MinePageState extends State { const Spacer(), Obx( () { + final anonymity = MineController.anonymity.value; return IconButton( iconSize: 40.0, padding: const EdgeInsets.all(8), style: const ButtonStyle( tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - tooltip: "${MineController.anonymity.value ? '退出' : '进入'}无痕模式", + tooltip: "${anonymity ? '退出' : '进入'}无痕模式", onPressed: MineController.onChangeAnonymity, - icon: MineController.anonymity.value + icon: anonymity ? const Icon(MdiIcons.incognito, size: 24) : const Icon(MdiIcons.incognitoOff, size: 24), ); @@ -89,190 +90,202 @@ class _MinePageState extends State { const SizedBox(height: 8), _header(theme), const SizedBox(height: 10), - Obx(() => userInfoBuild(theme)), + userInfoBuild(theme), ], ), ); } Widget userInfoBuild(ThemeData theme) { - UserInfoData userInfo = _mineController.userInfo.value; - LevelInfo? levelInfo = userInfo.levelInfo; TextStyle style = TextStyle( fontSize: theme.textTheme.titleMedium!.fontSize, color: theme.colorScheme.primary, fontWeight: FontWeight.bold, ); - final isVip = userInfo.vipStatus != null && userInfo.vipStatus! > 0; - return Column( - mainAxisSize: MainAxisSize.min, - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: _mineController.onLogin, - onLongPress: () => _mineController.onLogin(true), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - const SizedBox(width: 20), - userInfo.face != null - ? Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - src: userInfo.face, - semanticsLabel: '头像', - type: ImageType.avatar, + return Obx(() { + final UserInfoData userInfo = _mineController.userInfo.value; + final LevelInfo? levelInfo = userInfo.levelInfo; + final isVip = userInfo.vipStatus != null && userInfo.vipStatus! > 0; + final userStat = _mineController.userStat.value; + return Column( + mainAxisSize: MainAxisSize.min, + children: [ + GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: _mineController.onLogin, + onLongPress: () { + Feedback.forLongPress(context); + _mineController.onLogin(true); + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + const SizedBox(width: 20), + userInfo.face != null + ? Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + src: userInfo.face, + semanticsLabel: '头像', + type: ImageType.avatar, + width: 55, + height: 55, + ), + if (isVip) + Positioned( + right: -1, + bottom: -2, + child: Image.asset( + 'assets/images/big-vip.png', + height: 19, + semanticLabel: "大会员", + ), + ), + ], + ) + : ClipOval( + child: Image.asset( width: 55, height: 55, - ), - if (isVip) - Positioned( - right: -1, - bottom: -2, - child: Image.asset( - 'assets/images/big-vip.png', - height: 19, - semanticLabel: "大会员", - ), - ), - ], - ) - : ClipOval( - child: Image.asset( - width: 55, - height: 55, - 'assets/images/noface.jpeg', - semanticLabel: "默认头像", - ), - ), - const SizedBox(width: 16), - Expanded( - child: Column( - mainAxisSize: MainAxisSize.min, - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - spacing: 4, - children: [ - Flexible( - child: Text( - userInfo.uname ?? '点击头像登录', - style: theme.textTheme.titleMedium!.copyWith( - height: 1, - color: isVip && userInfo.vipType == 2 - ? context.vipColor - : null, - ), - ), - ), - Image.asset( - 'assets/images/lv/lv${levelInfo == null ? 0 : userInfo.isSeniorMember == 1 ? '6_s' : levelInfo.currentLevel}.png', - height: 10, - ), - ], - ), - const SizedBox(height: 8), - FittedBox( - child: Text.rich( - TextSpan( - children: [ - TextSpan( - text: '硬币 ', - style: TextStyle( - fontSize: theme.textTheme.labelSmall!.fontSize, - color: theme.colorScheme.outline, - ), - ), - TextSpan( - text: userInfo.money?.toString() ?? '-', - style: TextStyle( - fontSize: theme.textTheme.labelSmall!.fontSize, - fontWeight: FontWeight.bold, - color: theme.colorScheme.primary, - ), - ), - TextSpan( - text: " 经验 ", - style: TextStyle( - fontSize: theme.textTheme.labelSmall!.fontSize, - color: theme.colorScheme.outline, - ), - ), - TextSpan( - text: "${levelInfo?.currentExp ?? '-'}", - semanticsLabel: - "当前${levelInfo?.currentExp ?? '-'}", - style: TextStyle( - fontSize: theme.textTheme.labelSmall!.fontSize, - fontWeight: FontWeight.bold, - color: theme.colorScheme.primary, - ), - ), - TextSpan( - text: "/${levelInfo?.nextExp ?? '-'}", - semanticsLabel: "升级需${levelInfo?.nextExp ?? '-'}", - style: TextStyle( - fontSize: theme.textTheme.labelSmall!.fontSize, - color: theme.colorScheme.outline, - ), - ), - ], + 'assets/images/noface.jpeg', + semanticLabel: "默认头像", ), ), - ), - const SizedBox(height: 4), - LinearProgressIndicator( - minHeight: 2, - value: levelInfo != null - ? (levelInfo.currentExp! / levelInfo.nextExp!) - : 0, - backgroundColor: theme.colorScheme.inversePrimary, - valueColor: AlwaysStoppedAnimation( - theme.colorScheme.primary), - ), - ], - ), - ), - const SizedBox(width: 20), - ], - ), - ), - const SizedBox(height: 10), - Center( - child: SizedBox( - width: 240, - child: Row( - children: [ - _btn( - count: _mineController.userStat.value.dynamicCount, - countStyle: style, - name: '动态', - nameStyle: theme.textTheme.labelMedium, - onTap: _mineController.pushDynamic, - ), - _btn( - count: _mineController.userStat.value.following, - countStyle: style, - name: '关注', - nameStyle: theme.textTheme.labelMedium, - onTap: _mineController.pushFollow, - ), - _btn( - count: _mineController.userStat.value.follower, - countStyle: style, - name: '粉丝', - nameStyle: theme.textTheme.labelMedium, - onTap: _mineController.pushFans, + const SizedBox(width: 16), + Expanded( + child: Column( + mainAxisSize: MainAxisSize.min, + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Row( + spacing: 4, + children: [ + Flexible( + child: Text( + userInfo.uname ?? '点击头像登录', + style: theme.textTheme.titleMedium!.copyWith( + height: 1, + color: isVip && userInfo.vipType == 2 + ? context.vipColor + : null, + ), + ), + ), + Image.asset( + 'assets/images/lv/lv${levelInfo == null ? 0 : userInfo.isSeniorMember == 1 ? '6_s' : levelInfo.currentLevel}.png', + height: 10, + ), + ], + ), + const SizedBox(height: 8), + FittedBox( + child: Text.rich( + TextSpan( + children: [ + TextSpan( + text: '硬币 ', + style: TextStyle( + fontSize: + theme.textTheme.labelSmall!.fontSize, + color: theme.colorScheme.outline, + ), + ), + TextSpan( + text: userInfo.money?.toString() ?? '-', + style: TextStyle( + fontSize: + theme.textTheme.labelSmall!.fontSize, + fontWeight: FontWeight.bold, + color: theme.colorScheme.primary, + ), + ), + TextSpan( + text: " 经验 ", + style: TextStyle( + fontSize: + theme.textTheme.labelSmall!.fontSize, + color: theme.colorScheme.outline, + ), + ), + TextSpan( + text: "${levelInfo?.currentExp ?? '-'}", + semanticsLabel: + "当前${levelInfo?.currentExp ?? '-'}", + style: TextStyle( + fontSize: + theme.textTheme.labelSmall!.fontSize, + fontWeight: FontWeight.bold, + color: theme.colorScheme.primary, + ), + ), + TextSpan( + text: "/${levelInfo?.nextExp ?? '-'}", + semanticsLabel: + "升级需${levelInfo?.nextExp ?? '-'}", + style: TextStyle( + fontSize: + theme.textTheme.labelSmall!.fontSize, + color: theme.colorScheme.outline, + ), + ), + ], + ), + ), + ), + const SizedBox(height: 4), + LinearProgressIndicator( + minHeight: 2, + value: levelInfo != null + ? (levelInfo.currentExp! / levelInfo.nextExp!) + : 0, + backgroundColor: theme.colorScheme.inversePrimary, + valueColor: AlwaysStoppedAnimation( + theme.colorScheme.primary), + ), + ], + ), ), + const SizedBox(width: 20), ], ), ), - ), - const SizedBox(height: 20), - ], - ); + const SizedBox(height: 10), + Center( + child: SizedBox( + width: 240, + child: Row( + children: [ + _btn( + count: userStat.dynamicCount, + countStyle: style, + name: '动态', + nameStyle: theme.textTheme.labelMedium, + onTap: _mineController.pushDynamic, + ), + _btn( + count: userStat.following, + countStyle: style, + name: '关注', + nameStyle: theme.textTheme.labelMedium, + onTap: _mineController.pushFollow, + ), + _btn( + count: userStat.follower, + countStyle: style, + name: '粉丝', + nameStyle: theme.textTheme.labelMedium, + onTap: _mineController.pushFans, + ), + ], + ), + ), + ), + const SizedBox(height: 20), + ], + ); + }); } Widget _btn({ diff --git a/lib/pages/pgc_review/child/controller.dart b/lib/pages/pgc_review/child/controller.dart index 67e9f8bf4..01f7b607d 100644 --- a/lib/pages/pgc_review/child/controller.dart +++ b/lib/pages/pgc_review/child/controller.dart @@ -32,7 +32,8 @@ class PgcReviewController @override void checkIsEnd(int length) { - if (count.value != null && length >= count.value!) { + final count = this.count.value; + if (count != null && length >= count) { isEnd = true; } } diff --git a/lib/pages/pgc_review/child/view.dart b/lib/pages/pgc_review/child/view.dart index fe8864684..7bce2c698 100644 --- a/lib/pages/pgc_review/child/view.dart +++ b/lib/pages/pgc_review/child/view.dart @@ -375,12 +375,15 @@ class _PgcReviewChildPageState extends State mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Obx( - () => _controller.count.value == null - ? const SizedBox.shrink() - : Text( - '${NumUtil.numFormat(_controller.count.value)}条点评', - style: const TextStyle(fontSize: 13), - ), + () { + final count = _controller.count.value; + return count == null + ? const SizedBox.shrink() + : Text( + '${NumUtil.numFormat(count)}条点评', + style: const TextStyle(fontSize: 13), + ); + }, ), SizedBox( height: 35, diff --git a/lib/pages/pgc_review/post/view.dart b/lib/pages/pgc_review/post/view.dart index 0737fd4e6..ffb1bc3be 100644 --- a/lib/pages/pgc_review/post/view.dart +++ b/lib/pages/pgc_review/post/view.dart @@ -117,23 +117,26 @@ class _PgcReviewPostPanelState SizedBox( width: double.infinity, child: Obx( - () => Text( - switch (_score.value) { - 1 => '很差', - 2 => '较差', - 3 => '还行', - 4 => '很好', - 5 => '佳作', - _ => '轻触评分', - }, - textAlign: TextAlign.center, - style: TextStyle( - fontSize: 16, - color: _score.value == 0 - ? theme.colorScheme.outline - : const Color(0xFFFFAD35), - ), - ), + () { + final score = _score.value; + return Text( + switch (score) { + 1 => '很差', + 2 => '较差', + 3 => '还行', + 4 => '很好', + 5 => '佳作', + _ => '轻触评分', + }, + textAlign: TextAlign.center, + style: TextStyle( + fontSize: 16, + color: score == 0 + ? theme.colorScheme.outline + : const Color(0xFFFFAD35), + ), + ); + }, ), ), Padding( @@ -157,7 +160,8 @@ class _PgcReviewPostPanelState onTap: () => _shareFeed.value = !_shareFeed.value, child: Obx( () { - Color color = _shareFeed.value + final shareFeed = _shareFeed.value; + Color color = shareFeed ? theme.colorScheme.primary : theme.colorScheme.outline; return Row( @@ -165,7 +169,7 @@ class _PgcReviewPostPanelState children: [ Icon( size: 22, - _shareFeed.value + shareFeed ? Icons.check_box_outlined : Icons.check_box_outline_blank_outlined, color: color, diff --git a/lib/pages/rank/view.dart b/lib/pages/rank/view.dart index 978f57919..08bdfffa1 100644 --- a/lib/pages/rank/view.dart +++ b/lib/pages/rank/view.dart @@ -34,51 +34,56 @@ class _RankPageState extends State RankType.values.length, (index) => IntrinsicHeight( child: Obx( - () => Material( - color: index == _rankController.tabIndex.value - ? theme.colorScheme.onInverseSurface - : theme.colorScheme.surface, - child: InkWell( - onTap: () { - if (_rankController.tabIndex.value != index) { - _rankController.tabIndex.value = index; - _rankController.tabController.animateTo(index); - } else { - _rankController.animateToTop(); - } - }, - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Container( - height: double.infinity, - width: 3, - color: index == _rankController.tabIndex.value - ? theme.colorScheme.primary - : Colors.transparent, - ), - Expanded( - flex: 1, - child: Container( - alignment: Alignment.center, - padding: const EdgeInsets.symmetric(vertical: 7), - child: Text( - RankType.values[index].label, - style: TextStyle( - color: index == _rankController.tabIndex.value - ? theme.colorScheme.primary - : theme.colorScheme.onSurface, - fontSize: 15, + () { + final isCurr = index == _rankController.tabIndex.value; + return Material( + color: isCurr + ? theme.colorScheme.onInverseSurface + : theme.colorScheme.surface, + child: InkWell( + onTap: () { + if (isCurr) { + _rankController.animateToTop(); + } else { + _rankController + ..tabIndex.value = index + ..tabController.animateTo(index); + } + }, + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Container( + height: double.infinity, + width: 3, + color: isCurr + ? theme.colorScheme.primary + : Colors.transparent, + ), + Expanded( + flex: 1, + child: Container( + alignment: Alignment.center, + padding: + const EdgeInsets.symmetric(vertical: 7), + child: Text( + RankType.values[index].label, + style: TextStyle( + color: isCurr + ? theme.colorScheme.primary + : theme.colorScheme.onSurface, + fontSize: 15, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - maxLines: 1, - overflow: TextOverflow.ellipsis, ), ), - ), - ], + ], + ), ), - ), - ), + ); + }, ), ), ), diff --git a/lib/pages/search_trending/view.dart b/lib/pages/search_trending/view.dart index 239b79d7d..97aceb8cf 100644 --- a/lib/pages/search_trending/view.dart +++ b/lib/pages/search_trending/view.dart @@ -70,10 +70,11 @@ class _SearchTrendingPageState extends State { preferredSize: const Size.fromHeight(56), child: Obx( () { - final flag = removePadding || _scrollRatio.value >= 0.5; + final scrollRatio = _scrollRatio.value; + final flag = removePadding || scrollRatio >= 0.5; return AppBar( title: Opacity( - opacity: _scrollRatio.value, + opacity: scrollRatio, child: Text( 'bilibili热搜', style: TextStyle( @@ -81,8 +82,8 @@ class _SearchTrendingPageState extends State { ), ), ), - backgroundColor: theme.colorScheme.surface - .withValues(alpha: _scrollRatio.value), + backgroundColor: + theme.colorScheme.surface.withValues(alpha: scrollRatio), foregroundColor: flag ? null : Colors.white, systemOverlayStyle: flag ? null @@ -90,7 +91,7 @@ class _SearchTrendingPageState extends State { statusBarBrightness: Brightness.dark, statusBarIconBrightness: Brightness.light, ), - bottom: _scrollRatio.value == 1 + bottom: scrollRatio == 1 ? PreferredSize( preferredSize: const Size.fromHeight(1), child: Divider( diff --git a/lib/pages/sponsor_block/view.dart b/lib/pages/sponsor_block/view.dart index e0ba09fbb..2557498ad 100644 --- a/lib/pages/sponsor_block/view.dart +++ b/lib/pages/sponsor_block/view.dart @@ -485,6 +485,7 @@ class _SponsorBlockPageState extends State { return Builder( builder: (context) { Color color = _blockColor[index]; + final isDisable = item.second == SkipType.disable; return ListTile( dense: true, enabled: item.second != SkipType.disable, @@ -519,8 +520,7 @@ class _SponsorBlockPageState extends State { return PopupMenuButton( initialValue: item.second, onSelected: (e) { - final updateItem = e == SkipType.disable || - item.second == SkipType.disable; + final updateItem = isDisable || e == SkipType.disable; item.second = e; setting.put(SettingBoxKey.blockSettings, _blockSettings.map((e) => e.second.index).toList()); @@ -546,7 +546,7 @@ class _SponsorBlockPageState extends State { style: TextStyle( height: 1, fontSize: 14, - color: item.second == SkipType.disable + color: isDisable ? theme.colorScheme.outline .withValues(alpha: 0.7) : theme.colorScheme.secondary, @@ -556,7 +556,7 @@ class _SponsorBlockPageState extends State { Icon( MdiIcons.unfoldMoreHorizontal, size: MediaQuery.textScalerOf(context).scale(14), - color: item.second == SkipType.disable + color: isDisable ? theme.colorScheme.outline .withValues(alpha: 0.7) : theme.colorScheme.secondary, @@ -573,9 +573,7 @@ class _SponsorBlockPageState extends State { item.first.description, style: TextStyle( fontSize: 12, - color: item.second == SkipType.disable - ? null - : theme.colorScheme.outline, + color: isDisable ? null : theme.colorScheme.outline, ), ), ); diff --git a/lib/pages/subscription_detail/view.dart b/lib/pages/subscription_detail/view.dart index f4d5f4550..1a8d90cc0 100644 --- a/lib/pages/subscription_detail/view.dart +++ b/lib/pages/subscription_detail/view.dart @@ -164,12 +164,16 @@ class _SubDetailPageState extends State { ), const Spacer(), Obx( - () => _subDetailController.mediaCount.value == 0 - ? const SizedBox.shrink() - : Text( - '共${_subDetailController.mediaCount.value}条视频', - style: style, - ), + () { + final mediaCount = + _subDetailController.mediaCount.value; + return mediaCount == 0 + ? const SizedBox.shrink() + : Text( + '共$mediaCount条视频', + style: style, + ); + }, ), Obx( () => Text( diff --git a/lib/pages/video/controller.dart b/lib/pages/video/controller.dart index 6517f31d4..79fa1b4b0 100644 --- a/lib/pages/video/controller.dart +++ b/lib/pages/video/controller.dart @@ -255,17 +255,17 @@ class VideoDetailController extends GetxController var keys = Get.arguments.keys.toList(); if (keys.isNotEmpty) { if (keys.contains('pic')) { - cover.value = Get.arguments['pic']; + cover.value = Get.arguments['pic'] ?? ''; } else if (keys.contains('videoItem')) { var args = Get.arguments['videoItem']; try { - if (args.pic != null && args.pic != '') { - cover.value = args.pic; + if (args.cover != null && args.cover != '') { + cover.value = args.cover; } } catch (_) { try { - if (args.cover != null && args.cover != '') { - cover.value = args.cover; + if (args.pic != null && args.pic != '') { + cover.value = args.pic; } } catch (_) {} } diff --git a/lib/pages/video/introduction/pgc/view.dart b/lib/pages/video/introduction/pgc/view.dart index 6b54c0816..c68b5a290 100644 --- a/lib/pages/video/introduction/pgc/view.dart +++ b/lib/pages/video/introduction/pgc/view.dart @@ -124,7 +124,7 @@ class _PgcIntroPageState extends State Expanded( child: GestureDetector( onTap: () => widget.showIntroDetail( - item, pgcIntroController.videoTags), + item, pgcIntroController.videoTags.value), behavior: HitTestBehavior.opaque, child: SizedBox( height: isLandscape ? 115 : 115 / 0.75, @@ -147,55 +147,56 @@ class _PgcIntroPageState extends State ), ), Obx( - () => FilledButton.tonal( - style: FilledButton.styleFrom( - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, - padding: const EdgeInsets.symmetric( - horizontal: 20, - vertical: 10, + () { + final isFollowed = + pgcIntroController.isFollowed.value; + final followStatus = + pgcIntroController.followStatus.value; + return FilledButton.tonal( + style: FilledButton.styleFrom( + tapTargetSize: + MaterialTapTargetSize.shrinkWrap, + padding: const EdgeInsets.symmetric( + horizontal: 20, + vertical: 10, + ), + visualDensity: VisualDensity.compact, + foregroundColor: isFollowed + ? theme.colorScheme.outline + : null, + backgroundColor: isFollowed + ? theme.colorScheme.onInverseSurface + : null, ), - visualDensity: VisualDensity.compact, - foregroundColor: - pgcIntroController.isFollowed.value - ? theme.colorScheme.outline - : null, - backgroundColor: - pgcIntroController.isFollowed.value - ? theme.colorScheme.onInverseSurface - : null, - ), - onPressed: pgcIntroController - .followStatus.value == - -1 - ? null - : () { - if (pgcIntroController - .isFollowed.value) { - showPgcFollowDialog( - context: context, - type: pgcIntroController.type, - followStatus: pgcIntroController - .followStatus.value, - onUpdateStatus: (followStatus) { - if (followStatus == -1) { - pgcIntroController.pgcDel(); - } else { - pgcIntroController - .pgcUpdate(followStatus); - } - }, - ); - } else { - pgcIntroController.pgcAdd(); - } - }, - child: Text( - pgcIntroController.isFollowed.value - ? '已${pgcIntroController.type}' - : '${pgcIntroController.type}', - ), - ), + onPressed: followStatus == -1 + ? null + : () { + if (isFollowed) { + showPgcFollowDialog( + context: context, + type: pgcIntroController.type, + followStatus: followStatus, + onUpdateStatus: (followStatus) { + if (followStatus == -1) { + pgcIntroController.pgcDel(); + } else { + pgcIntroController + .pgcUpdate( + followStatus); + } + }, + ); + } else { + pgcIntroController.pgcAdd(); + } + }, + child: Text( + isFollowed + ? '已${pgcIntroController.type}' + : '${pgcIntroController.type}', + ), + ); + }, ), ], ), diff --git a/lib/pages/video/introduction/ugc/controller.dart b/lib/pages/video/introduction/ugc/controller.dart index 5f0e58870..92a256b55 100644 --- a/lib/pages/video/introduction/ugc/controller.dart +++ b/lib/pages/video/introduction/ugc/controller.dart @@ -10,6 +10,7 @@ import 'package:PiliPlus/http/search.dart'; import 'package:PiliPlus/http/user.dart'; import 'package:PiliPlus/http/video.dart'; import 'package:PiliPlus/member_card_info/data.dart'; +import 'package:PiliPlus/models_new/fav/fav_folder/data.dart'; import 'package:PiliPlus/models_new/triple/ugc_triple.dart'; import 'package:PiliPlus/models_new/video/video_ai_conclusion/data.dart'; import 'package:PiliPlus/models_new/video/video_ai_conclusion/model_result.dart'; @@ -145,10 +146,9 @@ class VideoIntroController extends CommonIntroController { } catch (_) {} } } catch (_) {} - if (videoDetail.value.pages != null && - videoDetail.value.pages!.isNotEmpty && - lastPlayCid.value == 0) { - lastPlayCid.value = videoDetail.value.pages!.first.cid!; + final pages = videoDetail.value.pages; + if (pages != null && pages.isNotEmpty && lastPlayCid.value == 0) { + lastPlayCid.value = pages.first.cid!; } queryUserStat(data.staff); } else { @@ -338,8 +338,9 @@ class VideoIntroController extends CommonIntroController { SmartDialog.showLoading(msg: '请求中'); queryVideoInFolder().then((res) async { if (res['status']) { - int defaultFolderId = favFolderData.value.list!.first.id; - bool notInDefFolder = favFolderData.value.list!.first.favState! == 0; + final first = favFolderData.value.list!.first; + int defaultFolderId = first.id; + bool notInDefFolder = first.favState! == 0; var result = await FavHttp.favVideo( aid: IdUtils.bv2av(bvid), addIds: notInDefFolder ? '$defaultFolderId' : '', @@ -505,8 +506,9 @@ class VideoIntroController extends CommonIntroController { rid: IdUtils.bv2av(bvid), ); if (result['status']) { - favFolderData.value = result['data']; - favIds = favFolderData.value.list + FavFolderData data = result['data']; + favFolderData.value = data; + favIds = data.list ?.where((item) => item.favState == 1) .map((item) => item.id) .toSet(); @@ -516,11 +518,11 @@ class VideoIntroController extends CommonIntroController { // 查询关注状态 Future queryFollowStatus() async { - if (videoDetail.value.owner == null || - videoDetail.value.staff?.isNotEmpty == true) { + final videoDetail = this.videoDetail.value; + if (videoDetail.owner == null || videoDetail.staff?.isNotEmpty == true) { return; } - var result = await UserHttp.hasFollow(videoDetail.value.owner!.mid!); + var result = await UserHttp.hasFollow(videoDetail.owner!.mid!); if (result['status']) { Map data = result['data']; if (data['special'] == 1) data['attribute'] = -10; diff --git a/lib/pages/video/introduction/ugc/view.dart b/lib/pages/video/introduction/ugc/view.dart index 4b039747b..f51be307f 100644 --- a/lib/pages/video/introduction/ugc/view.dart +++ b/lib/pages/video/introduction/ugc/view.dart @@ -259,12 +259,11 @@ class _VideoIntroPanelState extends State ), ], Obx(() { - if (introController - .videoTags.value.isNullOrEmpty) { + final videoTags = introController.videoTags.value; + if (videoTags.isNullOrEmpty) { return const SizedBox.shrink(); } - return _buildTags( - introController.videoTags.value!); + return _buildTags(videoTags!); }) ], ), @@ -366,86 +365,90 @@ class _VideoIntroPanelState extends State Widget _buildVideoTitle(ThemeData theme, VideoDetailData videoDetail, {bool isExpand = false}) { late final isDark = theme.brightness == Brightness.dark; - Widget child() => Text.rich( - TextSpan( - children: [ - if (videoDetailCtr.videoLabel.value.isNotEmpty) ...[ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Container( - padding: const EdgeInsets.symmetric( - horizontal: 4, - vertical: 2, - ), - decoration: BoxDecoration( - color: theme.colorScheme.secondaryContainer, - borderRadius: const BorderRadius.all(Radius.circular(4)), - ), - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Stack( - clipBehavior: Clip.none, - alignment: Alignment.center, - children: [ - Icon( - Icons.shield_outlined, - size: 16, - color: theme.colorScheme.onSecondaryContainer, - ), - Icon( - Icons.play_arrow_rounded, - size: 12, - color: theme.colorScheme.onSecondaryContainer, - ), - ], - ), - Text( - videoDetailCtr.videoLabel.value, - textScaler: TextScaler.noScaling, - strutStyle: const StrutStyle( - leading: 0, - height: 1, - fontSize: 13, - ), - style: TextStyle( - height: 1, - fontSize: 13, + Widget child() { + final videoLabel = videoDetailCtr.videoLabel.value; + return Text.rich( + TextSpan( + children: [ + if (videoLabel.isNotEmpty) ...[ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Container( + padding: const EdgeInsets.symmetric( + horizontal: 4, + vertical: 2, + ), + decoration: BoxDecoration( + color: theme.colorScheme.secondaryContainer, + borderRadius: const BorderRadius.all(Radius.circular(4)), + ), + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Stack( + clipBehavior: Clip.none, + alignment: Alignment.center, + children: [ + Icon( + Icons.shield_outlined, + size: 16, color: theme.colorScheme.onSecondaryContainer, ), + Icon( + Icons.play_arrow_rounded, + size: 12, + color: theme.colorScheme.onSecondaryContainer, + ), + ], + ), + Text( + videoLabel, + textScaler: TextScaler.noScaling, + strutStyle: const StrutStyle( + leading: 0, + height: 1, + fontSize: 13, ), - ], - ), + style: TextStyle( + height: 1, + fontSize: 13, + color: theme.colorScheme.onSecondaryContainer, + ), + ), + ], ), ), - const TextSpan(text: ' '), - ], - if (videoDetail.isUpowerExclusive == true) ...[ - _labelWidget( - '充电专属', - isDark - ? theme.colorScheme.error - : theme.colorScheme.errorContainer, - isDark - ? theme.colorScheme.onError - : theme.colorScheme.onErrorContainer, - ), - const TextSpan(text: ' '), - ] else if (videoDetail.rights?.isSteinGate == 1) ...[ - _labelWidget( - '互动视频', - theme.colorScheme.secondaryContainer, - theme.colorScheme.onSecondaryContainer, - ), - const TextSpan(text: ' '), - ], - TextSpan(text: videoDetail.title ?? ''), + ), + const TextSpan(text: ' '), ], - ), - maxLines: isExpand ? null : 2, - overflow: isExpand ? null : TextOverflow.ellipsis, - style: const TextStyle(fontSize: 16), - ); + if (videoDetail.isUpowerExclusive == true) ...[ + _labelWidget( + '充电专属', + isDark + ? theme.colorScheme.error + : theme.colorScheme.errorContainer, + isDark + ? theme.colorScheme.onError + : theme.colorScheme.onErrorContainer, + ), + const TextSpan(text: ' '), + ] else if (videoDetail.rights?.isSteinGate == 1) ...[ + _labelWidget( + '互动视频', + theme.colorScheme.secondaryContainer, + theme.colorScheme.onSecondaryContainer, + ), + const TextSpan(text: ' '), + ], + TextSpan(text: videoDetail.title ?? ''), + ], + ), + maxLines: isExpand ? null : 2, + overflow: isExpand ? null : TextOverflow.ellipsis, + style: const TextStyle(fontSize: 16), + ); + } + if (videoDetailCtr.plPlayerController.enableSponsorBlock) { return Obx(child); } diff --git a/lib/pages/video/medialist/view.dart b/lib/pages/video/medialist/view.dart index 164fa2297..2b2c04b04 100644 --- a/lib/pages/video/medialist/view.dart +++ b/lib/pages/video/medialist/view.dart @@ -93,16 +93,18 @@ class _MediaListPanelState backgroundColor: Colors.transparent, actions: [ Obx( - () => mediumButton( - tooltip: desc.value ? '顺序播放' : '倒序播放', - icon: desc.value - ? MdiIcons.sortAscending - : MdiIcons.sortDescending, - onPressed: () { - widget.onReverse(); - desc.value = !desc.value; - }, - ), + () { + final desc = this.desc.value; + return mediumButton( + tooltip: desc ? '顺序播放' : '倒序播放', + icon: + desc ? MdiIcons.sortAscending : MdiIcons.sortDescending, + onPressed: () { + widget.onReverse(); + this.desc.value = !desc; + }, + ); + }, ), mediumButton( tooltip: '关闭', diff --git a/lib/pages/video/member/view.dart b/lib/pages/video/member/view.dart index a7529688e..623f2dae4 100644 --- a/lib/pages/video/member/view.dart +++ b/lib/pages/video/member/view.dart @@ -129,12 +129,13 @@ class _HorizontalMemberPageState extends State { mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Obx( - () => Text( - _controller.count.value != -1 - ? '共${_controller.count.value}视频' - : '', - style: const TextStyle(fontSize: 13), - ), + () { + final count = _controller.count.value; + return Text( + count != -1 ? '共$count视频' : '', + style: const TextStyle(fontSize: 13), + ); + }, ), SizedBox( height: 35, diff --git a/lib/pages/video/note/controller.dart b/lib/pages/video/note/controller.dart index c0a5035fc..15be56d5d 100644 --- a/lib/pages/video/note/controller.dart +++ b/lib/pages/video/note/controller.dart @@ -27,7 +27,8 @@ class NoteListPageCtr @override void checkIsEnd(int length) { - if (count.value != -1 && length >= count.value) { + final count = this.count.value; + if (count != -1 && length >= count) { isEnd = true; } } diff --git a/lib/pages/video/note/view.dart b/lib/pages/video/note/view.dart index 5f20985dd..6d1ce0b7b 100644 --- a/lib/pages/video/note/view.dart +++ b/lib/pages/video/note/view.dart @@ -64,10 +64,10 @@ class _NoteListPageState extends CommonSlidePageState { titleSpacing: 16, toolbarHeight: 45, backgroundColor: Colors.transparent, - title: Obx( - () => Text( - '笔记${_controller.count.value == -1 ? '' : '(${_controller.count.value})'}'), - ), + title: Obx(() { + final count = _controller.count.value; + return Text('笔记${count == -1 ? '' : '($count)'}'); + }), bottom: PreferredSize( preferredSize: const Size.fromHeight(1), child: Divider( diff --git a/lib/pages/video/pay_coins/view.dart b/lib/pages/video/pay_coins/view.dart index 31f5cee1a..0f69fff06 100644 --- a/lib/pages/video/pay_coins/view.dart +++ b/lib/pages/video/pay_coins/view.dart @@ -389,11 +389,10 @@ class _PayCoinsPageState extends State children: [ GestureDetector( onTap: () { - _coinWithLike.value = !_coinWithLike.value; - GStorage.setting.put( - SettingBoxKey.coinWithLike, - _coinWithLike.value, - ); + final newVal = !_coinWithLike.value; + _coinWithLike.value = newVal; + GStorage.setting + .put(SettingBoxKey.coinWithLike, newVal); }, child: Row( mainAxisSize: MainAxisSize.min, diff --git a/lib/pages/video/reply_new/view.dart b/lib/pages/video/reply_new/view.dart index 6be457cd8..9c82d7e60 100644 --- a/lib/pages/video/reply_new/view.dart +++ b/lib/pages/video/reply_new/view.dart @@ -192,38 +192,40 @@ class _ReplyPageState extends CommonRichTextPubPageState { Expanded( child: Center( child: Obx( - () => TextButton( - style: TextButton.styleFrom( - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - padding: const EdgeInsets.all(13), - visualDensity: VisualDensity.compact, - foregroundColor: _syncToDynamic.value - ? themeData.colorScheme.secondary - : themeData.colorScheme.outline, - ), - onPressed: () => - _syncToDynamic.value = !_syncToDynamic.value, - child: Row( - spacing: 4, - mainAxisSize: MainAxisSize.min, - children: [ - Icon( - _syncToDynamic.value - ? Icons.check_box - : Icons.check_box_outline_blank, - size: 22, - ), - const Flexible( - child: Text( - '转到动态', - maxLines: 1, - style: TextStyle(height: 1), - strutStyle: StrutStyle(leading: 0, height: 1), + () { + final syncToDynamic = _syncToDynamic.value; + return TextButton( + style: TextButton.styleFrom( + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + padding: const EdgeInsets.all(13), + visualDensity: VisualDensity.compact, + foregroundColor: syncToDynamic + ? themeData.colorScheme.secondary + : themeData.colorScheme.outline, + ), + onPressed: () => _syncToDynamic.value = !syncToDynamic, + child: Row( + spacing: 4, + mainAxisSize: MainAxisSize.min, + children: [ + Icon( + syncToDynamic + ? Icons.check_box + : Icons.check_box_outline_blank, + size: 22, ), - ), - ], - ), - ), + const Flexible( + child: Text( + '转到动态', + maxLines: 1, + style: TextStyle(height: 1), + strutStyle: StrutStyle(leading: 0, height: 1), + ), + ), + ], + ), + ); + }, ), ), ), diff --git a/lib/pages/video/reply_reply/view.dart b/lib/pages/video/reply_reply/view.dart index 9db2725c9..42a4f4b0f 100644 --- a/lib/pages/video/reply_reply/view.dart +++ b/lib/pages/video/reply_reply/view.dart @@ -238,12 +238,15 @@ class _VideoReplyReplyPanelState mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ Obx( - () => _controller.count.value != -1 - ? Text( - '相关回复共${NumUtil.numFormat(_controller.count.value)}条', - style: const TextStyle(fontSize: 13), - ) - : const SizedBox.shrink(), + () { + final count = _controller.count.value; + return count != -1 + ? Text( + '相关回复共${NumUtil.numFormat(count)}条', + style: const TextStyle(fontSize: 13), + ) + : const SizedBox.shrink(); + }, ), SizedBox( height: 35, diff --git a/lib/pages/video/view.dart b/lib/pages/video/view.dart index fc993f903..286b82269 100644 --- a/lib/pages/video/view.dart +++ b/lib/pages/video/view.dart @@ -98,11 +98,13 @@ class _VideoDetailPageVState extends State bool isShowing = true; bool get isFullScreen => plPlayerController?.isFullScreen.value ?? false; - bool get _shouldShowSeasonPanel => - (videoIntroController.videoDetail.value.ugcSeason != null || - ((videoIntroController.videoDetail.value.pages?.length ?? 0) > 1)) && - context.orientation == Orientation.landscape && - videoDetailController.plPlayerController.horizontalSeasonPanel; + bool get _shouldShowSeasonPanel { + final videoDetail = videoIntroController.videoDetail.value; + return (videoDetail.ugcSeason != null || + ((videoDetail.pages?.length ?? 0) > 1)) && + context.orientation == Orientation.landscape && + videoDetailController.plPlayerController.horizontalSeasonPanel; + } bool get _horizontalPreview => context.orientation == Orientation.landscape && @@ -403,9 +405,9 @@ class _VideoDetailPageVState extends State } } super.didPopNext(); - videoDetailController.autoPlay.value = - !videoDetailController.isShowCover.value; - if (!videoDetailController.isShowCover.value) { + final isShowCover = videoDetailController.isShowCover.value; + videoDetailController.autoPlay.value = !isShowCover; + if (!isShowCover) { await videoDetailController.playerInit( autoplay: videoDetailController.playerStatus == PlayerStatus.playing, ); @@ -504,10 +506,10 @@ class _VideoDetailPageVState extends State preferredSize: const Size.fromHeight(0), child: Obx( () { - bool shouldShow = - videoDetailController.scrollRatio.value != 0 && - videoDetailController.scrollCtr.offset != 0 && - isPortrait; + final scrollRatio = videoDetailController.scrollRatio.value; + bool shouldShow = scrollRatio != 0 && + videoDetailController.scrollCtr.offset != 0 && + isPortrait; return Stack( clipBehavior: Clip.none, children: [ @@ -527,9 +529,7 @@ class _VideoDetailPageVState extends State if (shouldShow) AppBar( backgroundColor: themeData.colorScheme.surface - .withValues( - alpha: videoDetailController - .scrollRatio.value), + .withValues(alpha: scrollRatio), toolbarHeight: 0, systemOverlayStyle: Platform.isAndroid ? SystemUiOverlayStyle( @@ -1523,29 +1523,28 @@ class _VideoDetailPageVState extends State width: 38, height: 38, child: Obx( - () => IconButton( - onPressed: () { - videoDetailController - .plPlayerController.enableShowDanmaku.value = - !videoDetailController - .plPlayerController.enableShowDanmaku.value; - GStorage.setting.put( - SettingBoxKey.enableShowDanmaku, - videoDetailController - .plPlayerController.enableShowDanmaku.value); - }, - icon: Icon( - size: 22, - videoDetailController - .plPlayerController.enableShowDanmaku.value - ? CustomIcon.dm_on - : CustomIcon.dm_off, - color: videoDetailController - .plPlayerController.enableShowDanmaku.value - ? themeData.colorScheme.secondary - : themeData.colorScheme.outline, - ), - ), + () { + final enableShowDanmaku = videoDetailController + .plPlayerController.enableShowDanmaku.value; + return IconButton( + onPressed: () { + final newVal = !enableShowDanmaku; + videoDetailController.plPlayerController + .enableShowDanmaku.value = newVal; + GStorage.setting + .put(SettingBoxKey.enableShowDanmaku, newVal); + }, + icon: Icon( + size: 22, + enableShowDanmaku + ? CustomIcon.dm_on + : CustomIcon.dm_off, + color: enableShowDanmaku + ? themeData.colorScheme.secondary + : themeData.colorScheme.outline, + ), + ); + }, ), ), const SizedBox(width: 14), diff --git a/lib/pages/video/view_point/view.dart b/lib/pages/video/view_point/view.dart index db15e97bf..5ccde8ee3 100644 --- a/lib/pages/video/view_point/view.dart +++ b/lib/pages/video/view_point/view.dart @@ -100,10 +100,10 @@ class _ViewPointsPageState itemBuilder: (context, index) { Segment segment = videoDetailController.viewPointList[index]; if (currentIndex == -1 && segment.from != null && segment.to != null) { - if (videoDetailController.plPlayerController.positionSeconds.value >= - segment.from! && - videoDetailController.plPlayerController.positionSeconds.value < - segment.to!) { + final positionSeconds = + videoDetailController.plPlayerController.positionSeconds.value; + if (positionSeconds >= segment.from! && + positionSeconds < segment.to!) { currentIndex = index; } } diff --git a/lib/pages/video/widgets/header_control.dart b/lib/pages/video/widgets/header_control.dart index cff7a1ce2..4f2681a03 100644 --- a/lib/pages/video/widgets/header_control.dart +++ b/lib/pages/video/widgets/header_control.dart @@ -277,45 +277,53 @@ class HeaderControlState extends State { spacing: 10, children: [ Obx( - () => ActionRowLineItem( - iconData: Icons.flip, - onTap: () => widget.controller.flipX.value = - !widget.controller.flipX.value, - text: " 左右翻转 ", - selectStatus: widget.controller.flipX.value, - ), + () { + final flipX = widget.controller.flipX.value; + return ActionRowLineItem( + iconData: Icons.flip, + onTap: () => widget.controller.flipX.value = !flipX, + text: " 左右翻转 ", + selectStatus: flipX, + ); + }, ), Obx( - () => ActionRowLineItem( - icon: Transform.rotate( - angle: pi / 2, - child: Icon( - Icons.flip, - size: 13, - color: widget.controller.flipY.value - ? theme.colorScheme.onSecondaryContainer - : theme.colorScheme.outline, + () { + final flipY = widget.controller.flipY.value; + return ActionRowLineItem( + icon: Transform.rotate( + angle: pi / 2, + child: Icon( + Icons.flip, + size: 13, + color: flipY + ? theme.colorScheme.onSecondaryContainer + : theme.colorScheme.outline, + ), ), - ), - onTap: () { - widget.controller.flipY.value = - !widget.controller.flipY.value; - }, - text: " 上下翻转 ", - selectStatus: widget.controller.flipY.value, - ), + onTap: () { + widget.controller.flipY.value = !flipY; + }, + text: " 上下翻转 ", + selectStatus: flipY, + ); + }, ), Obx( - () => ActionRowLineItem( - iconData: Icons.headphones, - onTap: () { - widget.controller.onlyPlayAudio.value = - !widget.controller.onlyPlayAudio.value; - widget.videoDetailCtr.playerInit(); - }, - text: " 听视频 ", - selectStatus: widget.controller.onlyPlayAudio.value, - ), + () { + final onlyPlayAudio = + widget.controller.onlyPlayAudio.value; + return ActionRowLineItem( + iconData: Icons.headphones, + onTap: () { + widget.controller.onlyPlayAudio.value = + !onlyPlayAudio; + widget.videoDetailCtr.playerInit(); + }, + text: " 听视频 ", + selectStatus: onlyPlayAudio, + ); + }, ), Obx( () => ActionRowLineItem( @@ -2042,26 +2050,28 @@ class HeaderControlState extends State { width: 42, height: 34, child: Obx( - () => IconButton( - tooltip: - "${plPlayerController.enableShowDanmaku.value ? '关闭' : '开启'}弹幕", - style: ButtonStyle( - padding: WidgetStateProperty.all(EdgeInsets.zero), - ), - onPressed: () { - plPlayerController.enableShowDanmaku.value = - !plPlayerController.enableShowDanmaku.value; - setting.put(SettingBoxKey.enableShowDanmaku, - plPlayerController.enableShowDanmaku.value); - }, - icon: Icon( - plPlayerController.enableShowDanmaku.value - ? Icons.subtitles_outlined - : Icons.subtitles_off_outlined, - size: 19, - color: Colors.white, - ), - ), + () { + final enableShowDanmaku = + plPlayerController.enableShowDanmaku.value; + return IconButton( + tooltip: "${enableShowDanmaku ? '关闭' : '开启'}弹幕", + style: ButtonStyle( + padding: WidgetStateProperty.all(EdgeInsets.zero), + ), + onPressed: () { + final newVal = !enableShowDanmaku; + plPlayerController.enableShowDanmaku.value = newVal; + setting.put(SettingBoxKey.enableShowDanmaku, newVal); + }, + icon: Icon( + enableShowDanmaku + ? Icons.subtitles_outlined + : Icons.subtitles_off_outlined, + size: 19, + color: Colors.white, + ), + ); + }, ), ), if (Platform.isAndroid) diff --git a/lib/pages/whisper/view.dart b/lib/pages/whisper/view.dart index e3506b6a5..1e4af36e9 100644 --- a/lib/pages/whisper/view.dart +++ b/lib/pages/whisper/view.dart @@ -27,9 +27,10 @@ class _WhisperPageState extends State { title: const Text('消息'), actions: [ Obx(() { - if (_controller.outsideItem.value?.isNotEmpty == true) { + final outsideItem = _controller.outsideItem.value; + if (outsideItem?.isNotEmpty == true) { return Row( - children: _controller.outsideItem.value!.map((e) { + children: outsideItem!.map((e) { return IconButton( tooltip: e.hasTitle() ? e.title : null, onPressed: () => e.type.action( @@ -43,10 +44,11 @@ class _WhisperPageState extends State { return const SizedBox.shrink(); }), Obx(() { - if (_controller.threeDotItems.value?.isNotEmpty == true) { + final threeDotItems = _controller.threeDotItems.value; + if (threeDotItems?.isNotEmpty == true) { return PopupMenuButton( itemBuilder: (context) { - return _controller.threeDotItems.value! + return threeDotItems! .map((e) => PopupMenuItem( onTap: () => e.type.action( context: context, diff --git a/lib/pages/whisper_detail/view.dart b/lib/pages/whisper_detail/view.dart index 69d8bbf10..c8f026d9f 100644 --- a/lib/pages/whisper_detail/view.dart +++ b/lib/pages/whisper_detail/view.dart @@ -276,9 +276,10 @@ class _WhisperDetailPageState ), Obx( () { + final enablePublish = this.enablePublish.value; return IconButton( onPressed: () async { - if (enablePublish.value) { + if (enablePublish) { _whisperDetailController.sendMsg( message: editController.rawText, onClearText: editController.clear, @@ -325,10 +326,10 @@ class _WhisperDetailPageState } } }, - icon: Icon(enablePublish.value + icon: Icon(enablePublish ? Icons.send : Icons.add_photo_alternate_outlined), - tooltip: enablePublish.value ? '发送' : '图片', + tooltip: enablePublish ? '发送' : '图片', ); }, ), diff --git a/lib/pages/whisper_detail/widget/chat_item.dart b/lib/pages/whisper_detail/widget/chat_item.dart index 4ade41022..f911ec2cc 100644 --- a/lib/pages/whisper_detail/widget/chat_item.dart +++ b/lib/pages/whisper_detail/widget/chat_item.dart @@ -323,7 +323,7 @@ class ChatItem extends StatelessWidget { if (cid != null) { PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', - arguments: { + arguments: { 'pic': i['cover_url'], 'heroTag': Utils.makeHeroTag(bvid), }, @@ -413,7 +413,7 @@ class ChatItem extends StatelessWidget { PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', arguments: { - 'pic': content['thumb'], + 'pic': content['cover'], 'heroTag': Utils.makeHeroTag(bvid), }, ); @@ -496,7 +496,7 @@ class ChatItem extends StatelessWidget { if (cid != null) { PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', - arguments: { + arguments: { 'pic': content['thumb'], 'heroTag': Utils.makeHeroTag(bvid), }, diff --git a/lib/pages/whisper_secondary/view.dart b/lib/pages/whisper_secondary/view.dart index 97c3da1ac..9066cb9e5 100644 --- a/lib/pages/whisper_secondary/view.dart +++ b/lib/pages/whisper_secondary/view.dart @@ -36,10 +36,11 @@ class _WhisperSecPageState extends State { title: Text(widget.name), actions: [ Obx(() { - if (_controller.threeDotItems.value?.isNotEmpty == true) { + final threeDotItems = _controller.threeDotItems.value; + if (threeDotItems?.isNotEmpty == true) { return PopupMenuButton( itemBuilder: (context) { - return _controller.threeDotItems.value! + return threeDotItems! .map((e) => PopupMenuItem( onTap: () => e.type.action( context: context, diff --git a/lib/plugin/pl_player/view.dart b/lib/plugin/pl_player/view.dart index a2e0da824..e5a187a6d 100644 --- a/lib/plugin/pl_player/view.dart +++ b/lib/plugin/pl_player/view.dart @@ -1134,17 +1134,17 @@ class _PLVideoPlayerState extends State const Text('/', style: textStyle), const SizedBox(width: 2), Obx( - () => Text( - plPlayerController.durationSeconds.value - .inMinutes >= - 60 - ? printDurationWithHours( - plPlayerController - .durationSeconds.value) - : printDuration(plPlayerController - .durationSeconds.value), - style: textStyle, - ), + () { + final durationSeconds = + plPlayerController.durationSeconds.value; + return Text( + durationSeconds.inMinutes >= 60 + ? printDurationWithHours( + durationSeconds) + : printDuration(durationSeconds), + style: textStyle, + ); + }, ), ], ), @@ -1250,33 +1250,35 @@ class _PLVideoPlayerState extends State // 头部、底部控制条 Obx( - () => Positioned.fill( - child: ClipRect( - child: Column( - children: [ - AppBarAni( - controller: animationController, - visible: !plPlayerController.controlsLock.value && - plPlayerController.showControls.value, - position: 'top', - child: widget.headerControl, - ), - const Spacer(), - AppBarAni( - controller: animationController, - visible: !plPlayerController.controlsLock.value && - plPlayerController.showControls.value, - position: 'bottom', - child: widget.bottomControl ?? - BottomControl( - controller: plPlayerController, - buildBottomControl: buildBottomControl, - ), - ), - ], + () { + final visible = !plPlayerController.controlsLock.value && + plPlayerController.showControls.value; + return Positioned.fill( + child: ClipRect( + child: Column( + children: [ + AppBarAni( + controller: animationController, + visible: visible, + position: 'top', + child: widget.headerControl, + ), + const Spacer(), + AppBarAni( + controller: animationController, + visible: visible, + position: 'bottom', + child: widget.bottomControl ?? + BottomControl( + controller: plPlayerController, + buildBottomControl: buildBottomControl, + ), + ), + ], + ), ), - ), - ), + ); + }, ), // if (BuildConfig.isDebug) diff --git a/lib/utils/url_utils.dart b/lib/utils/url_utils.dart index e599312f4..2c9ae7266 100644 --- a/lib/utils/url_utils.dart +++ b/lib/utils/url_utils.dart @@ -54,7 +54,7 @@ class UrlUtils { if (cid != null) { PageUtils.toVideoPage( 'bvid=$bvid&cid=$cid', - arguments: { + arguments: { 'heroTag': Utils.makeHeroTag(bvid), }, preventDuplicates: false,