Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-09-19 15:32:46 +08:00
parent 099c7b4dff
commit 51c605f5d0
16 changed files with 227 additions and 171 deletions

View File

@@ -1,6 +1,7 @@
import 'package:PiliPlus/models_new/video/video_ai_conclusion/model_result.dart';
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
import 'package:PiliPlus/pages/video/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/utils/duration_utils.dart';
import 'package:flutter/gestures.dart';
import 'package:flutter/material.dart';
@@ -69,7 +70,7 @@ class _AiDetailState extends State<AiConclusionPanel>
SliverToBoxAdapter(
child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 14),
child: SelectableText(
child: selectableText(
widget.item.summary!,
style: const TextStyle(
fontSize: 15,
@@ -98,57 +99,59 @@ class _AiDetailState extends State<AiConclusionPanel>
itemCount: widget.item.outline!.length,
itemBuilder: (context, index) {
final item = widget.item.outline![index];
return Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (index != 0) const SizedBox(height: 10),
SelectableText(
item.title!,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
height: 1.5,
return SelectionArea(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
if (index != 0) const SizedBox(height: 10),
Text(
item.title!,
style: const TextStyle(
fontSize: 14,
fontWeight: FontWeight.bold,
height: 1.5,
),
),
),
const SizedBox(height: 6),
...?item.partOutline?.map(
(item) => Wrap(
children: [
SelectableText.rich(
TextSpan(
style: TextStyle(
fontSize: 14,
color: theme.colorScheme.onSurface,
height: 1.5,
),
children: [
TextSpan(
text: DurationUtils.formatDuration(
item.timestamp,
),
style: TextStyle(
color: theme.colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
try {
Get.find<VideoDetailController>(
tag: Get.arguments['heroTag'],
).plPlayerController.seekTo(
Duration(seconds: item.timestamp!),
);
} catch (_) {}
},
const SizedBox(height: 6),
...?item.partOutline?.map(
(item) => Wrap(
children: [
Text.rich(
TextSpan(
style: TextStyle(
fontSize: 14,
color: theme.colorScheme.onSurface,
height: 1.5,
),
const TextSpan(text: ' '),
TextSpan(text: item.content!),
],
children: [
TextSpan(
text: DurationUtils.formatDuration(
item.timestamp,
),
style: TextStyle(
color: theme.colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
try {
Get.find<VideoDetailController>(
tag: Get.arguments['heroTag'],
).plPlayerController.seekTo(
Duration(seconds: item.timestamp!),
);
} catch (_) {}
},
),
const TextSpan(text: ' '),
TextSpan(text: item.content!),
],
),
),
),
],
],
),
),
),
],
],
),
);
},
),

View File

@@ -277,7 +277,7 @@ class PgcIntroController extends CommonIntroController {
}
// 修改分P或番剧分集
Future<void> onChangeEpisode(BaseEpisodeItem episode) async {
Future<bool> onChangeEpisode(BaseEpisodeItem episode) async {
try {
final int epId = episode.epId ?? episode.id!;
final String bvid = episode.bvid ?? this.bvid;
@@ -285,7 +285,7 @@ class PgcIntroController extends CommonIntroController {
final int? cid =
episode.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid == null) {
return;
return false;
}
final String? cover = episode.cover;
@@ -323,8 +323,10 @@ class PgcIntroController extends CommonIntroController {
this.cid.value = cid;
queryOnlineTotal();
queryVideoIntro(episode as EpisodeItem);
return true;
} catch (e) {
if (kDebugMode) debugPrint('pgc onChangeEpisode: $e');
return false;
}
}

View File

@@ -9,6 +9,7 @@ import 'package:PiliPlus/models_new/video/video_tag/data.dart';
import 'package:PiliPlus/pages/common/slide/common_slide_page.dart';
import 'package:PiliPlus/pages/pgc_review/view.dart';
import 'package:PiliPlus/pages/search/widgets/search_text.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/utils/extension.dart';
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart' hide TabBarView;
@@ -108,7 +109,7 @@ class _IntroDetailState extends State<PgcIntroPanel>
bottom: MediaQuery.viewPaddingOf(context).bottom + 100,
),
children: [
SelectableText(
selectableText(
widget.item.title!,
style: const TextStyle(fontSize: 16),
),
@@ -152,7 +153,7 @@ class _IntroDetailState extends State<PgcIntroPanel>
style: theme.textTheme.titleMedium,
),
const SizedBox(height: 4),
SelectableText(
selectableText(
widget.item.evaluate!,
style: textStyle,
),

View File

@@ -463,7 +463,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
}
// 修改分P或番剧分集
Future<void> onChangeEpisode(
Future<bool> onChangeEpisode(
BaseEpisodeItem episode, {
bool isStein = false,
}) async {
@@ -473,7 +473,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
final int? cid =
episode.cid ?? await SearchHttp.ab2c(aid: aid, bvid: bvid);
if (cid == null) {
return;
return false;
}
final String? cover = episode.cover;
@@ -488,7 +488,7 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
cid: cid,
cover: cover,
);
return;
return false;
}
}
@@ -546,8 +546,10 @@ class UgcIntroController extends CommonIntroController with ReloadMixin {
this.cid.value = cid;
queryOnlineTotal();
return true;
} catch (e) {
if (kDebugMode) debugPrint('ugc onChangeEpisode: $e');
return false;
}
}

View File

@@ -15,6 +15,7 @@ import 'package:PiliPlus/pages/video/introduction/ugc/controller.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/action_item.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/page.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/season.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/selectable_text.dart';
import 'package:PiliPlus/pages/video/introduction/ugc/widgets/triple_state.dart';
import 'package:PiliPlus/utils/app_scheme.dart';
import 'package:PiliPlus/utils/date_utils.dart';
@@ -327,13 +328,9 @@ class _UgcIntroPanelState extends TripleState<UgcIntroPanel> {
),
if (videoDetail.descV2?.isNotEmpty == true) ...[
const SizedBox(height: 8),
SelectableText.rich(
selectableRichText(
style: const TextStyle(height: 1.4),
TextSpan(
children: [
buildContent(theme, videoDetail),
],
),
buildContent(theme, videoDetail),
),
],
Obx(() {
@@ -601,7 +598,7 @@ class _UgcIntroPanelState extends TripleState<UgcIntroPanel> {
caseSensitive: false,
);
InlineSpan buildContent(ThemeData theme, VideoDetailData content) {
TextSpan buildContent(ThemeData theme, VideoDetailData content) {
if (content.descV2.isNullOrEmpty) {
return const TextSpan();
}

View File

@@ -0,0 +1,38 @@
import 'package:PiliPlus/utils/utils.dart';
import 'package:flutter/material.dart';
Widget selectableText(
String text, {
TextStyle? style,
}) {
if (Utils.isDesktop) {
return SelectionArea(
child: Text(
style: style,
text,
),
);
}
return SelectableText(
style: style,
text,
);
}
Widget selectableRichText(
TextSpan textSpan, {
TextStyle? style,
}) {
if (Utils.isDesktop) {
return SelectionArea(
child: Text.rich(
style: style,
textSpan,
),
);
}
return SelectableText.rich(
style: style,
textSpan,
);
}