mod: intro panel

opt: pgc page

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-02-06 20:01:52 +08:00
parent c6e229d571
commit 331fd0d619
5 changed files with 434 additions and 413 deletions

View File

@@ -265,7 +265,7 @@ class _BangumiInfoState extends State<BangumiInfo>
Expanded( Expanded(
child: GestureDetector( child: GestureDetector(
onTap: showIntroDetail, onTap: showIntroDetail,
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.opaque,
child: SizedBox( child: SizedBox(
height: isLandscape ? 115 : 115 / 0.75, height: isLandscape ? 115 : 115 / 0.75,
child: Column( child: Column(

View File

@@ -82,48 +82,48 @@ class _BangumiPageState extends State<BangumiPage>
slivers: [ slivers: [
SliverToBoxAdapter( SliverToBoxAdapter(
child: Obx( child: Obx(
() => Visibility( () => _bangumiController.isLogin.value
visible: _bangumiController.isLogin.value, ? Column(
child: Column( children: [
children: [ Padding(
Padding( padding: const EdgeInsets.only(left: 16),
padding: const EdgeInsets.only(left: 16), child: Row(
child: Row( mainAxisAlignment: MainAxisAlignment.spaceBetween,
mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
children: [ Obx(
Obx( () => Text(
() => Text( '最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${_bangumiController.followCount.value == -1 ? '' : ' ${_bangumiController.followCount.value}'}',
'最近${widget.tabType == TabType.bangumi ? '追番' : '追剧'}${_bangumiController.followCount.value == -1 ? '' : ' ${_bangumiController.followCount.value}'}', style:
style: Theme.of(context).textTheme.titleMedium, Theme.of(context).textTheme.titleMedium,
), ),
),
IconButton(
tooltip: '刷新',
onPressed: () {
_bangumiController
..followPage = 1
..followEnd = false
..queryBangumiFollow();
},
icon: const Icon(
Icons.refresh,
size: 20,
),
),
],
), ),
IconButton( ),
tooltip: '刷新', SizedBox(
onPressed: () { height: Grid.smallCardWidth / 2 / 0.75 +
_bangumiController MediaQuery.textScalerOf(context).scale(50),
..followPage = 1 child: Obx(
..followEnd = false () => _buildFollowBody(
..queryBangumiFollow(); _bangumiController.followState.value),
},
icon: const Icon(
Icons.refresh,
size: 20,
),
), ),
], ),
), ],
), )
SizedBox( : const SizedBox.shrink(),
height: Grid.smallCardWidth / 2 / 0.75 +
MediaQuery.textScalerOf(context).scale(50),
child: Obx(
() => _buildFollowBody(
_bangumiController.followState.value),
),
),
],
),
),
), ),
), ),
SliverToBoxAdapter( SliverToBoxAdapter(

View File

@@ -127,7 +127,7 @@ class _MinePageState extends State<MinePage> {
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: [ children: [
GestureDetector( GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.opaque,
onTap: _mineController.onLogin, onTap: _mineController.onLogin,
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,

View File

@@ -308,223 +308,192 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
constraints.viewportMainAxisExtent * 1.25; constraints.viewportMainAxisExtent * 1.25;
return SliverPadding( return SliverPadding(
padding: const EdgeInsets.only( padding: const EdgeInsets.only(
left: StyleString.safeSpace, left: StyleString.safeSpace,
right: StyleString.safeSpace, right: StyleString.safeSpace,
top: 10), top: 10,
),
sliver: SliverToBoxAdapter( sliver: SliverToBoxAdapter(
child: GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: showIntroDetail,
child: Column( child: Column(
crossAxisAlignment: CrossAxisAlignment.start, crossAxisAlignment: CrossAxisAlignment.start,
children: [
Row(
children: [
Expanded(
child: videoItem['staff'] == null
? GestureDetector(
onTap: onPushMember,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
NetworkImgLayer(
type: 'avatar',
src: widget.loadingStatus
? videoItem['owner']?.face ?? ""
: videoDetail.owner!.face,
width: 35,
height: 35,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
widget.loadingStatus
? videoItem['owner']?.name ?? ""
: videoDetail.owner!.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
// color: t.colorScheme.primary,
),
// semanticsLabel: "UP主${owner.name}",
),
const SizedBox(height: 0),
Obx(
() => Text(
'${Utils.numFormat(videoIntroController.userStat.value['follower'])}粉丝',
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
),
],
),
),
followButton(context, t),
],
),
)
: SelfSizedHorizontalList(
gapSize: 25,
itemCount: videoItem['staff'].length,
childBuilder: (index) => GestureDetector(
onTap: () {
int? ownerMid = !widget.loadingStatus
? videoDetail.owner?.mid
: videoItem['owner']?.mid;
if (videoItem['staff'][index].mid == ownerMid &&
context.orientation ==
Orientation.landscape &&
_horizontalMemberPage) {
widget.onShowMemberPage(ownerMid);
} else {
Get.toNamed(
'/member?mid=${videoItem['staff'][index].mid}',
// arguments: {
// 'face':
// videoItem['staff'][index].face,
// 'heroTag': Utils.makeHeroTag(
// videoItem['staff'][index].mid),
// },
);
}
},
child: Row(
children: [
NetworkImgLayer(
type: 'avatar',
src: videoItem['staff'][index].face,
width: 35,
height: 35,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
const SizedBox(width: 5),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
videoItem['staff'][index].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: videoItem['staff'][index]
.vip
.status >
0 &&
videoItem['staff'][index]
.vip
.type ==
2
? context.vipColor
: null,
),
),
Text(
videoItem['staff'][index].title,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.colorScheme
.outline,
),
),
],
),
],
),
),
),
),
if (isHorizontal) ...[
const SizedBox(width: 10),
Expanded(child: actionGrid(context, videoIntroController)),
]
],
),
if (videoIntroController.videoDetail.value.argueMsg?.isNotEmpty ==
true &&
videoIntroController.showArgueMsg) ...[
const SizedBox(height: 8),
Container(
width: double.infinity,
decoration: BoxDecoration(
borderRadius: BorderRadius.circular(6),
color: Theme.of(context).colorScheme.secondaryContainer,
),
padding:
const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
child: Text.rich(
TextSpan(children: [
WidgetSpan(
alignment: PlaceholderAlignment.middle,
child: Icon(
size: 17,
Icons.warning_rounded,
color: Theme.of(context)
.colorScheme
.onSecondaryContainer,
),
),
TextSpan(
text:
' ${videoIntroController.videoDetail.value.argueMsg}')
]),
style: TextStyle(
fontSize: 13,
color: Theme.of(context).colorScheme.onSecondaryContainer,
),
),
)
],
const SizedBox(height: 8),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: showIntroDetail,
child: ExpandablePanel(
controller: videoIntroController.expandableCtr,
collapsed: GestureDetector(
onLongPress: () {
feedBack();
Utils.copyText(
'${videoDetail.title ?? videoItem['title'] ?? ''}');
},
child: _buildVideoTitle(),
),
expanded: GestureDetector(
onLongPress: () {
feedBack();
Utils.copyText(
'${videoDetail.title ?? videoItem['title'] ?? ''}');
},
child: _buildVideoTitle(true),
),
theme: const ExpandableThemeData(
animationDuration: Duration(milliseconds: 300),
scrollAnimationDuration: Duration(milliseconds: 300),
crossFadePoint: 0,
fadeCurve: Curves.ease,
sizeCurve: Curves.linear,
),
),
),
Stack(
children: [ children: [
GestureDetector( GestureDetector(
behavior: HitTestBehavior.translucent, behavior: HitTestBehavior.opaque,
onTap: showIntroDetail, onTap: () {},
child: Padding( child: Row(
padding: const EdgeInsets.only(top: 8), children: [
child: Row( Expanded(
child: videoItem['staff'] == null
? GestureDetector(
onTap: onPushMember,
child: Row(
mainAxisAlignment: MainAxisAlignment.center,
mainAxisSize: MainAxisSize.min,
children: [
NetworkImgLayer(
type: 'avatar',
src: widget.loadingStatus
? videoItem['owner']?.face ?? ""
: videoDetail.owner!.face,
width: 35,
height: 35,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
const SizedBox(width: 10),
Expanded(
child: Column(
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
widget.loadingStatus
? videoItem['owner']?.name ??
""
: videoDetail.owner!.name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
// color: t.colorScheme.primary,
),
// semanticsLabel: "UP主${owner.name}",
),
const SizedBox(height: 0),
Obx(
() => Text(
'${Utils.numFormat(videoIntroController.userStat.value['follower'])}粉丝',
style: TextStyle(
fontSize: 12,
color: t.colorScheme.outline,
),
),
),
],
),
),
followButton(context, t),
],
),
)
: SelfSizedHorizontalList(
gapSize: 25,
itemCount: videoItem['staff'].length,
childBuilder: (index) => GestureDetector(
onTap: () {
int? ownerMid = !widget.loadingStatus
? videoDetail.owner?.mid
: videoItem['owner']?.mid;
if (videoItem['staff'][index].mid ==
ownerMid &&
context.orientation ==
Orientation.landscape &&
_horizontalMemberPage) {
widget.onShowMemberPage(ownerMid);
} else {
Get.toNamed(
'/member?mid=${videoItem['staff'][index].mid}',
// arguments: {
// 'face':
// videoItem['staff'][index].face,
// 'heroTag': Utils.makeHeroTag(
// videoItem['staff'][index].mid),
// },
);
}
},
child: Row(
children: [
NetworkImgLayer(
type: 'avatar',
src: videoItem['staff'][index].face,
width: 35,
height: 35,
fadeInDuration: Duration.zero,
fadeOutDuration: Duration.zero,
),
const SizedBox(width: 5),
Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment:
CrossAxisAlignment.start,
children: [
Text(
videoItem['staff'][index].name,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 13,
color: videoItem['staff'][index]
.vip
.status >
0 &&
videoItem['staff']
[index]
.vip
.type ==
2
? context.vipColor
: null,
),
),
Text(
videoItem['staff'][index].title,
style: TextStyle(
fontSize: 12,
color: Theme.of(context)
.colorScheme
.outline,
),
),
],
),
],
),
),
),
),
if (isHorizontal) ...[
const SizedBox(width: 10),
Expanded(
child: actionGrid(context, videoIntroController)),
]
],
),
),
const SizedBox(height: 8),
ExpandablePanel(
controller: videoIntroController.expandableCtr,
collapsed: GestureDetector(
onLongPress: () {
feedBack();
Utils.copyText(
'${videoDetail.title ?? videoItem['title'] ?? ''}');
},
child: _buildVideoTitle(),
),
expanded: GestureDetector(
onLongPress: () {
feedBack();
Utils.copyText(
'${videoDetail.title ?? videoItem['title'] ?? ''}');
},
child: _buildVideoTitle(true),
),
theme: const ExpandableThemeData(
animationDuration: Duration(milliseconds: 300),
scrollAnimationDuration: Duration(milliseconds: 300),
crossFadePoint: 0,
fadeCurve: Curves.ease,
sizeCurve: Curves.linear,
),
),
const SizedBox(height: 8),
Stack(
children: [
Row(
children: <Widget>[ children: <Widget>[
statView( statView(
context: context, context: context,
@@ -577,169 +546,195 @@ class _VideoInfoState extends State<VideoInfo> with TickerProviderStateMixin {
), ),
], ],
), ),
), if (videoIntroController.enableAi)
), Positioned(
if (videoIntroController.enableAi) right: 10,
Positioned( top: 0,
right: 10, bottom: 0,
top: 0, child: Center(
bottom: 0, child: Semantics(
child: Center( label: 'AI总结',
child: Semantics( child: GestureDetector(
label: 'AI总结', onTap: () async {
child: GestureDetector( final res =
onTap: () async { await videoIntroController.aiConclusion();
final res = if (res['status']) {
await videoIntroController.aiConclusion(); widget.showAiBottomSheet();
if (res['status']) { }
widget.showAiBottomSheet(); },
} child: Image.asset('assets/images/ai.png',
}, height: 22),
child: ),
Image.asset('assets/images/ai.png', height: 22), ),
), ),
), )
),
)
],
),
GestureDetector(
behavior: HitTestBehavior.translucent,
onTap: showIntroDetail,
child: ExpandablePanel(
controller: videoIntroController.expandableCtr,
collapsed: const SizedBox.shrink(),
expanded: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
GestureDetector(
onTap: () {
Utils.copyText(
'${videoIntroController.videoDetail.value.bvid}');
},
child: Text(
videoIntroController.videoDetail.value.bvid ?? '',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.primary,
),
),
),
if (videoIntroController
.videoDetail.value.descV2.isNullOrEmpty.not) ...[
const SizedBox(height: 8),
SelectableText.rich(
style: const TextStyle(
height: 1.4,
// fontSize: 13,
),
TextSpan(
children: [
buildContent(context,
videoIntroController.videoDetail.value),
],
),
),
],
if (videoIntroController.videoTags is List &&
videoIntroController.videoTags.isNotEmpty) ...[
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: (videoIntroController.videoTags as List)
.map(
(item) => SearchText(
fontSize: 13,
text: item['tag_name'],
onTap: (_) => Get.toNamed('/searchResult',
parameters: {
'keyword': item['tag_name']
}),
onLongPress: (_) =>
Utils.copyText(item['tag_name']),
),
)
.toList(),
),
],
], ],
), ),
theme: const ExpandableThemeData( if (videoIntroController
animationDuration: Duration(milliseconds: 300), .videoDetail.value.argueMsg?.isNotEmpty ==
scrollAnimationDuration: Duration(milliseconds: 300), true &&
crossFadePoint: 0, videoIntroController.showArgueMsg) ...[
fadeCurve: Curves.ease, const SizedBox(height: 2),
sizeCurve: Curves.linear, Text.rich(
), TextSpan(
), children: [
), WidgetSpan(
Obx( alignment: PlaceholderAlignment.middle,
() => videoIntroController.queryVideoIntroData.value["status"] child: Icon(
? const SizedBox.shrink() size: 13,
: Center( Icons.error_outline,
child: TextButton.icon( color: Theme.of(context).colorScheme.outline,
icon: const Icon(Icons.refresh), ),
onPressed: () { ),
videoIntroController WidgetSpan(child: SizedBox(width: 2)),
.queryVideoIntroData.value["status"] = true; TextSpan(
videoIntroController.queryVideoIntro(); text:
if (videoDetailCtr.videoUrl.isNullOrEmpty && '${videoIntroController.videoDetail.value.argueMsg}',
videoDetailCtr.isQuerying.not) { )
videoDetailCtr.queryVideoUrl(); ],
}
},
label: const Text("点此重新加载"),
),
), ),
style: TextStyle(
fontSize: 12,
color: Theme.of(context).colorScheme.outline,
),
),
],
ExpandablePanel(
controller: videoIntroController.expandableCtr,
collapsed: const SizedBox.shrink(),
expanded: Column(
mainAxisSize: MainAxisSize.min,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8),
GestureDetector(
onTap: () {
Utils.copyText(
'${videoIntroController.videoDetail.value.bvid}');
},
child: Text(
videoIntroController.videoDetail.value.bvid ?? '',
style: TextStyle(
fontSize: 14,
color: Theme.of(context).colorScheme.primary,
),
),
),
if (videoIntroController
.videoDetail.value.descV2.isNullOrEmpty.not) ...[
const SizedBox(height: 8),
SelectableText.rich(
style: const TextStyle(
height: 1.4,
// fontSize: 13,
),
TextSpan(
children: [
buildContent(context,
videoIntroController.videoDetail.value),
],
),
),
],
if (videoIntroController.videoTags is List &&
videoIntroController.videoTags.isNotEmpty) ...[
const SizedBox(height: 8),
Wrap(
spacing: 8,
runSpacing: 8,
children: (videoIntroController.videoTags as List)
.map(
(item) => SearchText(
fontSize: 13,
text: item['tag_name'],
onTap: (_) => Get.toNamed('/searchResult',
parameters: {
'keyword': item['tag_name']
}),
onLongPress: (_) =>
Utils.copyText(item['tag_name']),
),
)
.toList(),
),
],
],
),
theme: const ExpandableThemeData(
animationDuration: Duration(milliseconds: 300),
scrollAnimationDuration: Duration(milliseconds: 300),
crossFadePoint: 0,
fadeCurve: Curves.ease,
sizeCurve: Curves.linear,
),
),
Obx(
() =>
videoIntroController.queryVideoIntroData.value["status"]
? const SizedBox.shrink()
: Center(
child: TextButton.icon(
icon: const Icon(Icons.refresh),
onPressed: () {
videoIntroController.queryVideoIntroData
.value["status"] = true;
videoIntroController.queryVideoIntro();
if (videoDetailCtr.videoUrl.isNullOrEmpty &&
videoDetailCtr.isQuerying.not) {
videoDetailCtr.queryVideoUrl();
}
},
label: const Text("点此重新加载"),
),
),
),
// 点赞收藏转发 布局样式1
// SingleChildScrollView(
// padding: const EdgeInsets.only(top: 7, bottom: 7),
// scrollDirection: Axis.horizontal,
// child: actionRow(
// context,
// videoIntroController,
// videoDetailCtr,
// ),
// ),
// 点赞收藏转发 布局样式2
if (!isHorizontal) ...[
const SizedBox(height: 8),
actionGrid(context, videoIntroController),
],
// 合集
if (!widget.loadingStatus &&
videoDetail.ugcSeason != null &&
(context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not)))
SeasonPanel(
heroTag: widget.heroTag,
ugcSeason: videoDetail.ugcSeason!,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
pages: videoDetail.pages,
videoIntroController: videoIntroController,
),
if (!widget.loadingStatus &&
videoDetail.pages != null &&
videoDetail.pages!.length > 1 &&
(context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not))) ...[
PagesPanel(
heroTag: widget.heroTag,
videoIntroController: videoIntroController,
bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
),
],
],
), ),
// 点赞收藏转发 布局样式1 ),
// SingleChildScrollView( ),
// padding: const EdgeInsets.only(top: 7, bottom: 7),
// scrollDirection: Axis.horizontal,
// child: actionRow(
// context,
// videoIntroController,
// videoDetailCtr,
// ),
// ),
// 点赞收藏转发 布局样式2
if (!isHorizontal) ...[
const SizedBox(height: 8),
actionGrid(context, videoIntroController),
],
// 合集
if (!widget.loadingStatus &&
videoDetail.ugcSeason != null &&
(context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not)))
SeasonPanel(
heroTag: widget.heroTag,
ugcSeason: videoDetail.ugcSeason!,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
pages: videoDetail.pages,
videoIntroController: videoIntroController,
),
if (!widget.loadingStatus &&
videoDetail.pages != null &&
videoDetail.pages!.length > 1 &&
(context.orientation != Orientation.landscape ||
(context.orientation == Orientation.landscape &&
videoDetailCtr.horizontalSeasonPanel.not))) ...[
PagesPanel(
heroTag: widget.heroTag,
videoIntroController: videoIntroController,
bvid: videoIntroController.bvid,
changeFuc: videoIntroController.changeSeasonOrbangu,
showEpisodes: widget.showEpisodes,
),
],
],
)),
); );
}, },
); );

View File

@@ -6,8 +6,10 @@ import 'package:PiliPlus/http/constants.dart';
import 'package:PiliPlus/http/init.dart'; import 'package:PiliPlus/http/init.dart';
import 'package:PiliPlus/http/loading_state.dart'; import 'package:PiliPlus/http/loading_state.dart';
import 'package:PiliPlus/models/common/dynamics_type.dart'; import 'package:PiliPlus/models/common/dynamics_type.dart';
import 'package:PiliPlus/models/common/tab_type.dart' hide tabsConfig;
import 'package:PiliPlus/models/user/info.dart'; import 'package:PiliPlus/models/user/info.dart';
import 'package:PiliPlus/models/user/stat.dart'; import 'package:PiliPlus/models/user/stat.dart';
import 'package:PiliPlus/pages/bangumi/controller.dart';
import 'package:PiliPlus/pages/dynamics/tab/controller.dart'; import 'package:PiliPlus/pages/dynamics/tab/controller.dart';
import 'package:PiliPlus/pages/live/controller.dart'; import 'package:PiliPlus/pages/live/controller.dart';
import 'package:PiliPlus/pages/main/controller.dart'; import 'package:PiliPlus/pages/main/controller.dart';
@@ -113,6 +115,18 @@ class LoginUtils {
..isLogin.value = true ..isLogin.value = true
..fetchLiveFollowing(); ..fetchLiveFollowing();
} catch (_) {} } catch (_) {}
try {
Get.find<BangumiController>(tag: TabType.bangumi.name)
..isLogin.value = true
..queryBangumiFollow();
} catch (_) {}
try {
Get.find<BangumiController>(tag: TabType.cinema.name)
..isLogin.value = true
..queryBangumiFollow();
} catch (_) {}
} else { } else {
// 获取用户信息失败 // 获取用户信息失败
SmartDialog.showNotify( SmartDialog.showNotify(
@@ -170,6 +184,18 @@ class LoginUtils {
Get.find<DynamicsTabController>(tag: tabsConfig[i]['tag']).onRefresh(); Get.find<DynamicsTabController>(tag: tabsConfig[i]['tag']).onRefresh();
} catch (_) {} } catch (_) {}
} }
try {
Get.find<BangumiController>(tag: TabType.bangumi.name)
..isLogin.value = false
..followState.value = LoadingState.loading();
} catch (_) {}
try {
Get.find<BangumiController>(tag: TabType.cinema.name)
..isLogin.value = false
..followState.value = LoadingState.loading();
} catch (_) {}
} }
static String buvid() { static String buvid() {