mirror of
https://github.com/HChaZZY/PiliPlus.git
synced 2025-12-06 09:13:48 +08:00
opt: get theme color
Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -128,79 +128,76 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
|
||||
late final _horizontalMemberPage = GStorage.horizontalMemberPage;
|
||||
|
||||
Widget _buildVideoTitle([bool isExpand = false]) => videoDetailCtr
|
||||
.enableSponsorBlock
|
||||
? Obx(
|
||||
() => 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.of(context).colorScheme.secondaryContainer,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Stack(
|
||||
alignment: Alignment.center,
|
||||
Widget _buildVideoTitle(ThemeData theme, [bool isExpand = false]) =>
|
||||
videoDetailCtr.enableSponsorBlock
|
||||
? Obx(
|
||||
() => 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: BorderRadius.circular(4),
|
||||
),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Icon(
|
||||
Icons.shield_outlined,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
Stack(
|
||||
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,
|
||||
),
|
||||
],
|
||||
),
|
||||
Icon(
|
||||
Icons.play_arrow_rounded,
|
||||
size: 12,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
Text(
|
||||
videoDetailCtr.videoLabel.value,
|
||||
textScaler: TextScaler.linear(1),
|
||||
strutStyle: StrutStyle(leading: 0, height: 1),
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 13,
|
||||
color: theme.colorScheme.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Text(
|
||||
videoDetailCtr.videoLabel.value,
|
||||
textScaler: TextScaler.linear(1),
|
||||
strutStyle: StrutStyle(leading: 0, height: 1),
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 13,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
TextSpan(text: ' '),
|
||||
],
|
||||
TextSpan(
|
||||
text: '${videoDetail.title ?? videoItem['title'] ?? ''}'),
|
||||
],
|
||||
),
|
||||
maxLines: isExpand ? null : 2,
|
||||
overflow: isExpand ? null : TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
'${videoDetail.title ?? videoItem['title'] ?? ''}',
|
||||
maxLines: isExpand ? null : 2,
|
||||
overflow: isExpand ? null : TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
);
|
||||
TextSpan(text: ' '),
|
||||
],
|
||||
TextSpan(
|
||||
text:
|
||||
'${videoDetail.title ?? videoItem['title'] ?? ''}'),
|
||||
],
|
||||
),
|
||||
maxLines: isExpand ? null : 2,
|
||||
overflow: isExpand ? null : TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
),
|
||||
)
|
||||
: Text(
|
||||
'${videoDetail.title ?? videoItem['title'] ?? ''}',
|
||||
maxLines: isExpand ? null : 2,
|
||||
overflow: isExpand ? null : TextOverflow.ellipsis,
|
||||
style: const TextStyle(fontSize: 16),
|
||||
);
|
||||
|
||||
void handleState(Future Function() action) async {
|
||||
if (isProcessing.not) {
|
||||
@@ -263,7 +260,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData themeData = Theme.of(context);
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return SliverLayoutBuilder(
|
||||
builder: (BuildContext context, SliverConstraints constraints) {
|
||||
bool isHorizontal = context.orientation == Orientation.landscape &&
|
||||
@@ -350,8 +347,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
'${Utils.numFormat(videoIntroController.userStat['follower'])}粉丝 ${videoIntroController.userStat['archive_count'] != null ? '${Utils.numFormat(videoIntroController.userStat['archive_count'])}视频' : ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
themeData.colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -362,7 +358,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
),
|
||||
),
|
||||
),
|
||||
followButton(context, themeData),
|
||||
followButton(context, theme),
|
||||
] else
|
||||
Expanded(
|
||||
child: SelfSizedHorizontalList(
|
||||
@@ -409,9 +405,8 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
child: Container(
|
||||
decoration: BoxDecoration(
|
||||
shape: BoxShape.circle,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.surface,
|
||||
color:
|
||||
theme.colorScheme.surface,
|
||||
),
|
||||
child: Icon(
|
||||
Icons.offline_bolt,
|
||||
@@ -461,16 +456,14 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
const EdgeInsets.all(
|
||||
2),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
color: theme.colorScheme
|
||||
.secondaryContainer,
|
||||
shape: BoxShape.circle,
|
||||
),
|
||||
child: Icon(
|
||||
MdiIcons.plus,
|
||||
size: 16,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
color: theme.colorScheme
|
||||
.onSecondaryContainer,
|
||||
),
|
||||
),
|
||||
@@ -508,9 +501,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
videoItem['staff'][index].title,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -537,7 +528,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
Utils.copyText(
|
||||
'${videoDetail.title ?? videoItem['title'] ?? ''}');
|
||||
},
|
||||
child: _buildVideoTitle(),
|
||||
child: _buildVideoTitle(theme),
|
||||
),
|
||||
expanded: GestureDetector(
|
||||
onLongPress: () {
|
||||
@@ -545,7 +536,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
Utils.copyText(
|
||||
'${videoDetail.title ?? videoItem['title'] ?? ''}');
|
||||
},
|
||||
child: _buildVideoTitle(true),
|
||||
child: _buildVideoTitle(theme, true),
|
||||
),
|
||||
theme: const ExpandableThemeData(
|
||||
animationDuration: Duration(milliseconds: 300),
|
||||
@@ -566,7 +557,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
value: Utils.numFormat(!widget.loadingStatus
|
||||
? videoDetail.stat?.view ?? '-'
|
||||
: videoItem['stat']?.view ?? '-'),
|
||||
textColor: themeData.colorScheme.outline,
|
||||
textColor: theme.colorScheme.outline,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
StatDanMu(
|
||||
@@ -575,7 +566,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
value: Utils.numFormat(!widget.loadingStatus
|
||||
? videoDetail.stat?.danmaku ?? '-'
|
||||
: videoItem['stat']?.danmu ?? '-'),
|
||||
textColor: themeData.colorScheme.outline,
|
||||
textColor: theme.colorScheme.outline,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
Text(
|
||||
@@ -586,7 +577,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
formatType: 'detail'),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: themeData.colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
if (MineController.anonymity.value) ...<Widget>[
|
||||
@@ -594,7 +585,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
Icon(
|
||||
MdiIcons.incognito,
|
||||
size: 15,
|
||||
color: themeData.colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
semanticLabel: '无痕',
|
||||
),
|
||||
],
|
||||
@@ -605,7 +596,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
'${videoIntroController.total.value}人在看',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: themeData.colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -656,7 +647,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
child: Icon(
|
||||
size: 13,
|
||||
Icons.error_outline,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
WidgetSpan(child: SizedBox(width: 2)),
|
||||
@@ -668,7 +659,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
),
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -689,7 +680,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
videoIntroController.videoDetail.value.bvid ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -702,7 +693,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
),
|
||||
TextSpan(
|
||||
children: [
|
||||
buildContent(context,
|
||||
buildContent(theme,
|
||||
videoIntroController.videoDetail.value),
|
||||
],
|
||||
),
|
||||
@@ -1013,7 +1004,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
]);
|
||||
}
|
||||
|
||||
InlineSpan buildContent(BuildContext context, VideoDetailData content) {
|
||||
InlineSpan buildContent(ThemeData theme, VideoDetailData content) {
|
||||
final List descV2 = content.descV2!;
|
||||
// type
|
||||
// 1 普通文本
|
||||
@@ -1039,8 +1030,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary),
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
PiliScheme.videoPush(aid, null);
|
||||
@@ -1057,8 +1047,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary),
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
PiliScheme.videoPush(null, matchStr);
|
||||
@@ -1072,8 +1061,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style:
|
||||
TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||
style: TextStyle(color: theme.colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
try {
|
||||
@@ -1094,8 +1082,7 @@ class _VideoInfoState extends State<VideoInfo> {
|
||||
);
|
||||
return TextSpan(children: spanChildren);
|
||||
case 2:
|
||||
final Color colorSchemePrimary =
|
||||
Theme.of(context).colorScheme.primary;
|
||||
final Color colorSchemePrimary = theme.colorScheme.primary;
|
||||
final String heroTag = Utils.makeHeroTag(currentDesc.bizId);
|
||||
return TextSpan(
|
||||
text: '@${currentDesc.rawText}',
|
||||
|
||||
@@ -127,10 +127,13 @@ class ActionItemState extends State<ActionItem>
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return widget.expand == false ? _buildItem : Expanded(child: _buildItem);
|
||||
final theme = Theme.of(context);
|
||||
return widget.expand == false
|
||||
? _buildItem(theme)
|
||||
: Expanded(child: _buildItem(theme));
|
||||
}
|
||||
|
||||
Widget get _buildItem => Semantics(
|
||||
Widget _buildItem(ThemeData theme) => Semantics(
|
||||
label: (widget.text ?? "") +
|
||||
(widget.selectStatus ? "已" : "") +
|
||||
widget.semanticsLabel,
|
||||
@@ -160,7 +163,7 @@ class ActionItemState extends State<ActionItem>
|
||||
CustomPaint(
|
||||
size: const Size(28, 28),
|
||||
painter: _ArcPainter(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
sweepAngle: _animation!.value,
|
||||
),
|
||||
)
|
||||
@@ -172,9 +175,8 @@ class ActionItemState extends State<ActionItem>
|
||||
: widget.icon.icon,
|
||||
size: 18,
|
||||
color: widget.selectStatus
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: widget.icon.color ??
|
||||
Theme.of(context).colorScheme.outline,
|
||||
? theme.colorScheme.primary
|
||||
: widget.icon.color ?? theme.colorScheme.outline,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -193,10 +195,9 @@ class ActionItemState extends State<ActionItem>
|
||||
key: ValueKey<String>(widget.text!),
|
||||
style: TextStyle(
|
||||
color: widget.selectStatus
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.outline,
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
),
|
||||
semanticsLabel: "",
|
||||
),
|
||||
|
||||
@@ -23,10 +23,11 @@ class ActionRowItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Material(
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.primaryContainer.withOpacity(0.6)
|
||||
: Theme.of(context).highlightColor.withOpacity(0.2),
|
||||
? theme.colorScheme.primaryContainer.withOpacity(0.6)
|
||||
: theme.highlightColor.withOpacity(0.2),
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
@@ -47,8 +48,8 @@ class ActionRowItem extends StatelessWidget {
|
||||
Icon(icon!.icon!,
|
||||
size: 13,
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.onSecondaryContainer),
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSecondaryContainer),
|
||||
const SizedBox(width: 6),
|
||||
],
|
||||
AnimatedOpacity(
|
||||
@@ -64,11 +65,8 @@ class ActionRowItem extends StatelessWidget {
|
||||
text ?? '',
|
||||
key: ValueKey<String>(text ?? ''),
|
||||
style: TextStyle(
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelMedium!.fontSize),
|
||||
color: selectStatus ? theme.colorScheme.primary : null,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize),
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -61,6 +61,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Scaffold(
|
||||
appBar: AppBar(
|
||||
title: Text(_mediaId != null ? '编辑' : '创建'),
|
||||
@@ -94,7 +95,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
),
|
||||
body: _mediaId != null
|
||||
? _titleController.text.isNotEmpty
|
||||
? _buildBody
|
||||
? _buildBody(theme)
|
||||
: _errMsg?.isNotEmpty == true
|
||||
? Center(
|
||||
child: CustomScrollView(
|
||||
@@ -108,11 +109,11 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
),
|
||||
)
|
||||
: Center(child: CircularProgressIndicator())
|
||||
: _buildBody,
|
||||
: _buildBody(theme),
|
||||
);
|
||||
}
|
||||
|
||||
void _pickImg() async {
|
||||
void _pickImg(ThemeData theme) async {
|
||||
try {
|
||||
XFile? pickedFile = await _imagePicker.pickImage(
|
||||
source: ImageSource.gallery,
|
||||
@@ -124,9 +125,8 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
uiSettings: [
|
||||
AndroidUiSettings(
|
||||
toolbarTitle: '裁剪',
|
||||
toolbarColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
toolbarWidgetColor:
|
||||
Theme.of(context).colorScheme.onSecondaryContainer,
|
||||
toolbarColor: theme.colorScheme.secondaryContainer,
|
||||
toolbarWidgetColor: theme.colorScheme.onSecondaryContainer,
|
||||
aspectRatioPresets: [
|
||||
CropAspectRatioPreset.ratio16x9,
|
||||
],
|
||||
@@ -167,12 +167,12 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
|
||||
dynamic leadingStyle = TextStyle(fontSize: 14);
|
||||
|
||||
Widget get _buildBody => SingleChildScrollView(
|
||||
Widget _buildBody(ThemeData theme) => SingleChildScrollView(
|
||||
child: Column(
|
||||
children: [
|
||||
if (_attr == null || !Utils.isDefaultFav(_attr!)) ...[
|
||||
ListTile(
|
||||
tileColor: Theme.of(context).colorScheme.onInverseSurface,
|
||||
tileColor: theme.colorScheme.onInverseSurface,
|
||||
onTap: () {
|
||||
EasyThrottle.throttle(
|
||||
'imagePicker', const Duration(milliseconds: 500),
|
||||
@@ -192,7 +192,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
dense: true,
|
||||
onTap: () {
|
||||
Get.back();
|
||||
_pickImg();
|
||||
_pickImg(theme);
|
||||
},
|
||||
title: const Text(
|
||||
'替换封面',
|
||||
@@ -217,7 +217,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
},
|
||||
);
|
||||
} else {
|
||||
_pickImg();
|
||||
_pickImg(theme);
|
||||
}
|
||||
});
|
||||
},
|
||||
@@ -248,7 +248,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
const SizedBox(width: 10),
|
||||
Icon(
|
||||
Icons.keyboard_arrow_right,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -256,7 +256,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
const SizedBox(height: 16),
|
||||
],
|
||||
ListTile(
|
||||
tileColor: Theme.of(context).colorScheme.onInverseSurface,
|
||||
tileColor: theme.colorScheme.onInverseSurface,
|
||||
leading: Text.rich(
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
@@ -269,7 +269,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.error,
|
||||
color: theme.colorScheme.error,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
@@ -289,7 +289,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: _attr != null && Utils.isDefaultFav(_attr!)
|
||||
? Theme.of(context).colorScheme.outline
|
||||
? theme.colorScheme.outline
|
||||
: null,
|
||||
),
|
||||
inputFormatters: [
|
||||
@@ -300,7 +300,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
hintText: '名称',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
@@ -313,7 +313,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
const SizedBox(height: 16),
|
||||
if (_attr == null || !Utils.isDefaultFav(_attr!)) ...[
|
||||
ListTile(
|
||||
tileColor: Theme.of(context).colorScheme.onInverseSurface,
|
||||
tileColor: theme.colorScheme.onInverseSurface,
|
||||
title: Row(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -324,9 +324,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
text: '简介',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
@@ -351,7 +349,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
hintText: '可填写简介',
|
||||
hintStyle: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
border: OutlineInputBorder(
|
||||
borderSide: BorderSide.none,
|
||||
@@ -372,7 +370,7 @@ class _CreateFavPageState extends State<CreateFavPage> {
|
||||
_isPublic = !_isPublic;
|
||||
});
|
||||
},
|
||||
tileColor: Theme.of(context).colorScheme.onInverseSurface,
|
||||
tileColor: theme.colorScheme.onInverseSurface,
|
||||
leading: Text(
|
||||
'公开',
|
||||
style: leadingStyle,
|
||||
|
||||
@@ -31,6 +31,7 @@ class _FavPanelState extends State<FavPanel> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return NotificationListener<DraggableScrollableNotification>(
|
||||
onNotification: (notification) {
|
||||
if (notification.extent <= 1e-5) {
|
||||
@@ -62,7 +63,7 @@ class _FavPanelState extends State<FavPanel> {
|
||||
},
|
||||
icon: Icon(
|
||||
Icons.add,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
label: const Text('新建收藏夹'),
|
||||
style: TextButton.styleFrom(
|
||||
@@ -156,7 +157,7 @@ class _FavPanelState extends State<FavPanel> {
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).disabledColor.withOpacity(0.08),
|
||||
color: theme.disabledColor.withOpacity(0.08),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
@@ -177,9 +178,8 @@ class _FavPanelState extends State<FavPanel> {
|
||||
horizontal: -1,
|
||||
vertical: -2,
|
||||
),
|
||||
foregroundColor: Theme.of(context).colorScheme.outline,
|
||||
backgroundColor:
|
||||
Theme.of(context).colorScheme.onInverseSurface,
|
||||
foregroundColor: theme.colorScheme.outline,
|
||||
backgroundColor: theme.colorScheme.onInverseSurface,
|
||||
),
|
||||
child: const Text('取消'),
|
||||
),
|
||||
|
||||
@@ -68,6 +68,7 @@ class _GroupPanelState extends State<GroupPanel> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return NotificationListener<DraggableScrollableNotification>(
|
||||
onNotification: (notification) {
|
||||
if (notification.extent <= 1e-5) {
|
||||
@@ -159,7 +160,7 @@ class _GroupPanelState extends State<GroupPanel> {
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).disabledColor.withOpacity(0.08),
|
||||
color: theme.disabledColor.withOpacity(0.08),
|
||||
),
|
||||
Padding(
|
||||
padding: EdgeInsets.only(
|
||||
@@ -175,8 +176,8 @@ class _GroupPanelState extends State<GroupPanel> {
|
||||
onPressed: () => onSave(),
|
||||
style: TextButton.styleFrom(
|
||||
padding: const EdgeInsets.only(left: 30, right: 30),
|
||||
foregroundColor: Theme.of(context).colorScheme.onPrimary,
|
||||
backgroundColor: Theme.of(context).colorScheme.primary,
|
||||
foregroundColor: theme.colorScheme.onPrimary,
|
||||
backgroundColor: theme.colorScheme.primary,
|
||||
),
|
||||
child: Text(showDefaultBtn ? '保存至默认分组' : '保存'),
|
||||
),
|
||||
|
||||
@@ -10,9 +10,10 @@ class MenuRow extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Container(
|
||||
width: double.infinity,
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
color: theme.colorScheme.surface,
|
||||
padding: const EdgeInsets.only(top: 9, bottom: 9, left: 12),
|
||||
child: SingleChildScrollView(
|
||||
scrollDirection: Axis.horizontal,
|
||||
@@ -50,11 +51,11 @@ class MenuRow extends StatelessWidget {
|
||||
}
|
||||
|
||||
Widget actionRowLineItem(
|
||||
BuildContext context, Function? onTap, bool? loadingStatus, String? text,
|
||||
ThemeData theme, Function? onTap, bool? loadingStatus, String? text,
|
||||
{bool selectStatus = false}) {
|
||||
return Material(
|
||||
color: selectStatus
|
||||
? Theme.of(context).highlightColor.withOpacity(0.2)
|
||||
? theme.highlightColor.withOpacity(0.2)
|
||||
: Colors.transparent,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
@@ -70,7 +71,7 @@ class MenuRow extends StatelessWidget {
|
||||
border: Border.all(
|
||||
color: selectStatus
|
||||
? Colors.transparent
|
||||
: Theme.of(context).highlightColor.withOpacity(0.2),
|
||||
: theme.highlightColor.withOpacity(0.2),
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -84,8 +85,8 @@ class MenuRow extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.onSurface
|
||||
: Theme.of(context).colorScheme.outline),
|
||||
? theme.colorScheme.onSurface
|
||||
: theme.colorScheme.outline),
|
||||
),
|
||||
),
|
||||
],
|
||||
@@ -115,9 +116,10 @@ class ActionRowLineItem extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Material(
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.secondaryContainer
|
||||
? theme.colorScheme.secondaryContainer
|
||||
: Colors.transparent,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(30)),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
@@ -133,7 +135,7 @@ class ActionRowLineItem extends StatelessWidget {
|
||||
border: Border.all(
|
||||
color: selectStatus
|
||||
? Colors.transparent
|
||||
: Theme.of(context).colorScheme.secondaryContainer,
|
||||
: theme.colorScheme.secondaryContainer,
|
||||
),
|
||||
),
|
||||
child: Row(
|
||||
@@ -144,8 +146,8 @@ class ActionRowLineItem extends StatelessWidget {
|
||||
iconData,
|
||||
size: 13,
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
? theme.colorScheme.onSecondaryContainer
|
||||
: theme.colorScheme.outline,
|
||||
)
|
||||
else if (icon != null)
|
||||
icon!,
|
||||
@@ -157,8 +159,8 @@ class ActionRowLineItem extends StatelessWidget {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: selectStatus
|
||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||
: Theme.of(context).colorScheme.outline),
|
||||
? theme.colorScheme.onSecondaryContainer
|
||||
: theme.colorScheme.outline),
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -87,6 +87,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Column(
|
||||
children: <Widget>[
|
||||
if (widget.showEpisodes != null)
|
||||
@@ -102,7 +103,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
overflow: TextOverflow.ellipsis,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -145,7 +146,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
right: i != pages.length - 1 ? 10 : 0,
|
||||
),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
@@ -175,7 +176,7 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
if (isCurrentIndex) ...<Widget>[
|
||||
Image.asset(
|
||||
'assets/images/live.png',
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
height: 12,
|
||||
semanticLabel: "正在播放:",
|
||||
),
|
||||
@@ -188,8 +189,8 @@ class _PagesPanelState extends State<PagesPanel> {
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: isCurrentIndex
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.onSurface,
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.onSurface,
|
||||
),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
))
|
||||
|
||||
@@ -88,6 +88,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
if (episodes.isEmpty) {
|
||||
return const SizedBox.shrink();
|
||||
}
|
||||
final theme = Theme.of(context);
|
||||
return Builder(builder: (BuildContext context) {
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(
|
||||
@@ -96,7 +97,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
right: 2,
|
||||
),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
child: InkWell(
|
||||
@@ -117,14 +118,14 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
Expanded(
|
||||
child: Text(
|
||||
'合集:${videoDetail.ugcSeason!.title!}',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
style: theme.textTheme.labelMedium,
|
||||
overflow: TextOverflow.ellipsis,
|
||||
),
|
||||
),
|
||||
const SizedBox(width: 15),
|
||||
Image.asset(
|
||||
'assets/images/live.png',
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
height: 12,
|
||||
semanticLabel: "正在播放:",
|
||||
),
|
||||
@@ -132,7 +133,7 @@ class _SeasonPanelState extends State<SeasonPanel> {
|
||||
Obx(
|
||||
() => Text(
|
||||
'${currentIndex.value + 1}/${episodes.length}',
|
||||
style: Theme.of(context).textTheme.labelMedium,
|
||||
style: theme.textTheme.labelMedium,
|
||||
semanticsLabel:
|
||||
'第${currentIndex.value + 1}集,共${episodes.length}集',
|
||||
),
|
||||
|
||||
@@ -78,12 +78,13 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final theme = Theme.of(context);
|
||||
return Obx(
|
||||
() => _buildUserPage(_controller.userState.value),
|
||||
() => _buildUserPage(theme, _controller.userState.value),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildUserPage(LoadingState userState) {
|
||||
Widget _buildUserPage(ThemeData theme, LoadingState userState) {
|
||||
return switch (userState) {
|
||||
Loading() => loadingWidget,
|
||||
Success() => Column(
|
||||
@@ -102,10 +103,11 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
_buildUserInfo(userState.response),
|
||||
_buildUserInfo(theme, userState.response),
|
||||
const SizedBox(height: 5),
|
||||
Expanded(
|
||||
child: Obx(() => _buildVideoList(_controller.loadingState.value)),
|
||||
child: Obx(
|
||||
() => _buildVideoList(theme, _controller.loadingState.value)),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -120,13 +122,13 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
};
|
||||
}
|
||||
|
||||
Widget get _buildSliverHeader {
|
||||
Widget _buildSliverHeader(ThemeData theme) {
|
||||
return SliverPersistentHeader(
|
||||
pinned: false,
|
||||
floating: true,
|
||||
delegate: CustomSliverPersistentHeaderDelegate(
|
||||
extent: 40,
|
||||
bgColor: Theme.of(context).colorScheme.surface,
|
||||
bgColor: theme.colorScheme.surface,
|
||||
child: Container(
|
||||
height: 40,
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
|
||||
@@ -153,14 +155,14 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
icon: Icon(
|
||||
Icons.sort,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
label: Obx(
|
||||
() => Text(
|
||||
_controller.order.value == 'pubdate' ? '最新发布' : '最多播放',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -173,7 +175,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildVideoList(LoadingState loadingState) {
|
||||
Widget _buildVideoList(ThemeData theme, LoadingState loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => loadingWidget,
|
||||
Success() => Material(
|
||||
@@ -185,7 +187,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
parent: ClampingScrollPhysics(),
|
||||
),
|
||||
slivers: [
|
||||
_buildSliverHeader,
|
||||
_buildSliverHeader(theme),
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
bottom: MediaQuery.of(context).padding.bottom + 80,
|
||||
@@ -234,19 +236,19 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
};
|
||||
}
|
||||
|
||||
Widget _buildUserInfo(MemberInfoModel memberInfoModel) {
|
||||
Widget _buildUserInfo(ThemeData theme, MemberInfoModel memberInfoModel) {
|
||||
return Row(
|
||||
children: [
|
||||
const SizedBox(width: 16),
|
||||
_buildAvatar(memberInfoModel.face),
|
||||
const SizedBox(width: 10),
|
||||
Expanded(child: _buildInfo(memberInfoModel)),
|
||||
Expanded(child: _buildInfo(theme, memberInfoModel)),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
_buildInfo(MemberInfoModel memberInfoModel) => Column(
|
||||
_buildInfo(ThemeData theme, MemberInfoModel memberInfoModel) => Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
@@ -281,6 +283,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
children: List.generate(5, (index) {
|
||||
if (index % 2 == 0) {
|
||||
return _buildChildInfo(
|
||||
theme: theme,
|
||||
title: const ['粉丝', '关注', '获赞'][index ~/ 2],
|
||||
num: index == 0
|
||||
? _controller.userStat['follower'] != null
|
||||
@@ -307,7 +310,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
width: 20,
|
||||
child: VerticalDivider(
|
||||
width: 1,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -321,10 +324,10 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
backgroundColor: memberInfoModel.isFollowed == true
|
||||
? Theme.of(context).colorScheme.onInverseSurface
|
||||
? theme.colorScheme.onInverseSurface
|
||||
: null,
|
||||
foregroundColor: memberInfoModel.isFollowed == true
|
||||
? Theme.of(context).colorScheme.outline
|
||||
? theme.colorScheme.outline
|
||||
: null,
|
||||
padding: const EdgeInsets.all(0),
|
||||
visualDensity: const VisualDensity(
|
||||
@@ -389,6 +392,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
);
|
||||
|
||||
Widget _buildChildInfo({
|
||||
required ThemeData theme,
|
||||
required String title,
|
||||
required dynamic num,
|
||||
required VoidCallback onTap,
|
||||
@@ -399,7 +403,7 @@ class _HorizontalMemberPageState extends State<HorizontalMemberPage> {
|
||||
'$num$title',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -50,87 +50,91 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildPage => Scaffold(
|
||||
key: _key,
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Scaffold(
|
||||
backgroundColor: Colors.transparent,
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
toolbarHeight: 45,
|
||||
title: Obx(
|
||||
() => Text(
|
||||
'笔记${_controller.count.value == -1 ? '' : '(${_controller.count.value})'}'),
|
||||
),
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(1),
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
icon: Icons.clear,
|
||||
onPressed: Get.back,
|
||||
size: 32,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
toolbarHeight: 45,
|
||||
title: Obx(
|
||||
() => Text(
|
||||
'笔记${_controller.count.value == -1 ? '' : '(${_controller.count.value})'}'),
|
||||
),
|
||||
body: enableSlide
|
||||
? slideList(Obx(() => _buildBody(_controller.loadingState.value)))
|
||||
: Obx(() => _buildBody(_controller.loadingState.value)),
|
||||
bottomNavigationBar: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 6,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 6,
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(1),
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: theme.colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
width: 0.5,
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
icon: Icons.clear,
|
||||
onPressed: Get.back,
|
||||
size: 32,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: enableSlide
|
||||
? slideList(theme,
|
||||
Obx(() => _buildBody(theme, _controller.loadingState.value)))
|
||||
: Obx(() => _buildBody(theme, _controller.loadingState.value)),
|
||||
bottomNavigationBar: Container(
|
||||
padding: EdgeInsets.only(
|
||||
left: 12,
|
||||
right: 12,
|
||||
top: 6,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 6,
|
||||
),
|
||||
width: double.infinity,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
border: Border(
|
||||
top: BorderSide(
|
||||
width: 0.5,
|
||||
color: theme.colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
),
|
||||
child: FilledButton.tonal(
|
||||
style: FilledButton.styleFrom(
|
||||
tapTargetSize: MaterialTapTargetSize.shrinkWrap,
|
||||
padding: EdgeInsets.zero,
|
||||
shape: RoundedRectangleBorder(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
),
|
||||
onPressed: () {
|
||||
if (!Accounts.main.isLogin) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
}
|
||||
_key.currentState?.showBottomSheet(
|
||||
(context) => WebviewPageNew(
|
||||
oid: widget.oid,
|
||||
title: widget.title,
|
||||
url:
|
||||
'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}',
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('开始记笔记'),
|
||||
),
|
||||
onPressed: () {
|
||||
if (!Accounts.main.isLogin) {
|
||||
SmartDialog.showToast('账号未登录');
|
||||
return;
|
||||
}
|
||||
_key.currentState?.showBottomSheet(
|
||||
(context) => WebviewPageNew(
|
||||
oid: widget.oid,
|
||||
title: widget.title,
|
||||
url:
|
||||
'https://www.bilibili.com/h5/note-app?oid=${widget.oid}&pagefrom=ugcvideo&is_stein_gate=${widget.isStein ? 1 : 0}',
|
||||
),
|
||||
);
|
||||
},
|
||||
child: const Text('开始记笔记'),
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState<List<dynamic>?> loadingState) {
|
||||
Widget _buildBody(
|
||||
ThemeData theme, LoadingState<List<dynamic>?> loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => CustomScrollView(
|
||||
physics: const NeverScrollableScrollPhysics(),
|
||||
@@ -158,15 +162,12 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
||||
_controller.onLoadMore();
|
||||
}
|
||||
return _itemWidget(
|
||||
context, loadingState.response![index]);
|
||||
context, theme, loadingState.response![index]);
|
||||
},
|
||||
itemCount: loadingState.response!.length,
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.outline
|
||||
.withOpacity(0.1),
|
||||
color: theme.colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
SliverToBoxAdapter(
|
||||
@@ -193,7 +194,7 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
||||
);
|
||||
}
|
||||
|
||||
Widget _itemWidget(BuildContext context, dynamic item) {
|
||||
Widget _itemWidget(BuildContext context, ThemeData theme, dynamic item) {
|
||||
return InkWell(
|
||||
onTap: () {
|
||||
if (item['web_url'] != null && item['web_url'] != '') {
|
||||
@@ -235,7 +236,7 @@ Widget _itemWidget(BuildContext context, dynamic item) {
|
||||
0 &&
|
||||
item['author']?['vip_info']?['type'] == 2
|
||||
? context.vipColor
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
: theme.colorScheme.outline,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
@@ -251,7 +252,7 @@ Widget _itemWidget(BuildContext context, dynamic item) {
|
||||
Text(
|
||||
item['pubtime'],
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: 12,
|
||||
),
|
||||
),
|
||||
@@ -261,18 +262,16 @@ Widget _itemWidget(BuildContext context, dynamic item) {
|
||||
item['summary'],
|
||||
style: TextStyle(
|
||||
height: 1.75,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.bodyMedium!.fontSize,
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
),
|
||||
),
|
||||
if (item['web_url'] != null && item['web_url'] != '')
|
||||
Text(
|
||||
'查看全部',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
height: 1.75,
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.bodyMedium!.fontSize,
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -50,352 +50,363 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
plPlayerController.position.value.inMilliseconds / 1000;
|
||||
|
||||
@override
|
||||
Widget get buildPage => Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('提交片段'),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '添加片段',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list?.insert(
|
||||
0,
|
||||
PostSegmentModel(
|
||||
segment: Pair(
|
||||
first: 0,
|
||||
second: currentPos,
|
||||
),
|
||||
category: SegmentType.sponsor,
|
||||
actionType: ActionType.skip,
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('提交片段'),
|
||||
actions: [
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '添加片段',
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list?.insert(
|
||||
0,
|
||||
PostSegmentModel(
|
||||
segment: Pair(
|
||||
first: 0,
|
||||
second: currentPos,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icons.add,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
icon: Icons.close,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: enableSlide ? slideList() : buildList,
|
||||
);
|
||||
category: SegmentType.sponsor,
|
||||
actionType: ActionType.skip,
|
||||
),
|
||||
);
|
||||
});
|
||||
},
|
||||
icon: Icons.add,
|
||||
),
|
||||
const SizedBox(width: 10),
|
||||
iconButton(
|
||||
context: context,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
icon: Icons.close,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
),
|
||||
body: enableSlide ? slideList(theme) : buildList(theme),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildList => list?.isNotEmpty == true
|
||||
? Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
list!.length,
|
||||
(index) => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color:
|
||||
Theme.of(context).colorScheme.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (list![index].actionType !=
|
||||
ActionType.full) ...[
|
||||
Widget buildList(ThemeData theme) {
|
||||
return list?.isNotEmpty == true
|
||||
? Stack(
|
||||
children: [
|
||||
SingleChildScrollView(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
child: Column(
|
||||
children: [
|
||||
...List.generate(
|
||||
list!.length,
|
||||
(index) => Stack(
|
||||
clipBehavior: Clip.none,
|
||||
children: [
|
||||
Container(
|
||||
width: double.infinity,
|
||||
margin: const EdgeInsets.symmetric(
|
||||
horizontal: 16,
|
||||
vertical: 5,
|
||||
),
|
||||
padding: const EdgeInsets.all(12),
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(12),
|
||||
),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (list![index].actionType !=
|
||||
ActionType.full) ...[
|
||||
Wrap(
|
||||
runSpacing: 8,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: segmentWidget(
|
||||
theme,
|
||||
isFirst: true,
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
if (list![index].category !=
|
||||
SegmentType.poi_highlight)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: segmentWidget(
|
||||
theme,
|
||||
isFirst: false,
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
Wrap(
|
||||
runSpacing: 8,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: segmentWidget(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
),
|
||||
),
|
||||
if (list![index].category !=
|
||||
SegmentType.poi_highlight)
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: segmentWidget(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
children: [
|
||||
const Text('分类: '),
|
||||
PopupMenuButton<SegmentType>(
|
||||
initialValue: list![index].category,
|
||||
onSelected: (item) async {
|
||||
list![index].category = item;
|
||||
List<ActionType> constraintList =
|
||||
segmentType2ActionType(item);
|
||||
if (constraintList
|
||||
.contains(
|
||||
list![index].actionType)
|
||||
.not) {
|
||||
list![index].actionType =
|
||||
constraintList.first;
|
||||
}
|
||||
switch (item) {
|
||||
case SegmentType.poi_highlight:
|
||||
updateSegment(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
value: list![index]
|
||||
.segment
|
||||
.first,
|
||||
);
|
||||
break;
|
||||
case SegmentType.exclusive_access:
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
break;
|
||||
case _:
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) => SegmentType
|
||||
.values
|
||||
.map((item) =>
|
||||
PopupMenuItem<SegmentType>(
|
||||
value: item,
|
||||
child: Text(item.title),
|
||||
))
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index].category.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: theme
|
||||
.colorScheme.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons.unfoldMoreHorizontal,
|
||||
size: MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color:
|
||||
theme.colorScheme.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
],
|
||||
Wrap(
|
||||
runSpacing: 8,
|
||||
spacing: 16,
|
||||
children: [
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('分类: '),
|
||||
PopupMenuButton<SegmentType>(
|
||||
initialValue: list![index].category,
|
||||
onSelected: (item) async {
|
||||
list![index].category = item;
|
||||
List<ActionType> constraintList =
|
||||
segmentType2ActionType(item);
|
||||
if (constraintList
|
||||
.contains(list![index].actionType)
|
||||
.not) {
|
||||
list![index].actionType =
|
||||
constraintList.first;
|
||||
}
|
||||
switch (item) {
|
||||
case SegmentType.poi_highlight:
|
||||
updateSegment(
|
||||
isFirst: false,
|
||||
index: index,
|
||||
value:
|
||||
list![index].segment.first,
|
||||
);
|
||||
break;
|
||||
case SegmentType.exclusive_access:
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('行为类别: '),
|
||||
PopupMenuButton<ActionType>(
|
||||
initialValue: list![index].actionType,
|
||||
onSelected: (item) async {
|
||||
list![index].actionType = item;
|
||||
if (item == ActionType.full) {
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
break;
|
||||
case _:
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) => SegmentType
|
||||
.values
|
||||
.map((item) =>
|
||||
PopupMenuItem<SegmentType>(
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) => ActionType
|
||||
.values
|
||||
.map(
|
||||
(item) =>
|
||||
PopupMenuItem<ActionType>(
|
||||
enabled:
|
||||
segmentType2ActionType(
|
||||
list![index]
|
||||
.category)
|
||||
.contains(item),
|
||||
value: item,
|
||||
child: Text(item.title),
|
||||
))
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index].category.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index].actionType.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: theme
|
||||
.colorScheme.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
Icon(
|
||||
MdiIcons.unfoldMoreHorizontal,
|
||||
size: MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color:
|
||||
theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons.unfoldMoreHorizontal,
|
||||
size: MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
const Text('行为类别: '),
|
||||
PopupMenuButton<ActionType>(
|
||||
initialValue: list![index].actionType,
|
||||
onSelected: (item) async {
|
||||
list![index].actionType = item;
|
||||
if (item == ActionType.full) {
|
||||
updateSegment(
|
||||
isFirst: true,
|
||||
index: index,
|
||||
value: 0,
|
||||
);
|
||||
}
|
||||
setState(() {});
|
||||
},
|
||||
itemBuilder: (context) => ActionType
|
||||
.values
|
||||
.map(
|
||||
(item) =>
|
||||
PopupMenuItem<ActionType>(
|
||||
enabled: segmentType2ActionType(
|
||||
list![index].category)
|
||||
.contains(item),
|
||||
value: item,
|
||||
child: Text(item.title),
|
||||
),
|
||||
)
|
||||
.toList(),
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
Text(
|
||||
list![index].actionType.title,
|
||||
style: TextStyle(
|
||||
height: 1,
|
||||
fontSize: 14,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
strutStyle: StrutStyle(
|
||||
height: 1,
|
||||
leading: 0,
|
||||
),
|
||||
),
|
||||
Icon(
|
||||
MdiIcons.unfoldMoreHorizontal,
|
||||
size: MediaQuery.textScalerOf(
|
||||
context)
|
||||
.scale(14),
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.secondary,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 4,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '移除',
|
||||
icon: Icons.clear,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list!.removeAt(index);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 4,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '预览',
|
||||
icon: Icons.preview_outlined,
|
||||
onPressed: () async {
|
||||
if (widget.plPlayerController
|
||||
.videoPlayerController !=
|
||||
null) {
|
||||
int start = max(
|
||||
0,
|
||||
(list![index].segment.first * 1000).toInt() -
|
||||
1,
|
||||
);
|
||||
await widget
|
||||
.plPlayerController.videoPlayerController!
|
||||
.seek(
|
||||
Duration(milliseconds: start),
|
||||
);
|
||||
if (widget.plPlayerController
|
||||
.videoPlayerController!.state.playing.not) {
|
||||
await widget
|
||||
.plPlayerController.videoPlayerController!
|
||||
.play();
|
||||
}
|
||||
if (start != 0) {
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 1));
|
||||
}
|
||||
widget.plPlayerController.videoPlayerController!
|
||||
.seek(
|
||||
Duration(
|
||||
milliseconds:
|
||||
(list![index].segment.second * 1000)
|
||||
.toInt(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
SizedBox(
|
||||
height: 88 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
right: 16,
|
||||
bottom: 16 + MediaQuery.paddingOf(context).bottom,
|
||||
child: FloatingActionButton(
|
||||
tooltip: '提交',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('确定无误再提交'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
_onPost();
|
||||
},
|
||||
child: const Text('确定提交'),
|
||||
),
|
||||
],
|
||||
Positioned(
|
||||
top: 0,
|
||||
right: 4,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '移除',
|
||||
icon: Icons.clear,
|
||||
onPressed: () {
|
||||
setState(() {
|
||||
list!.removeAt(index);
|
||||
});
|
||||
},
|
||||
),
|
||||
),
|
||||
Positioned(
|
||||
top: 0,
|
||||
left: 4,
|
||||
child: iconButton(
|
||||
context: context,
|
||||
size: 26,
|
||||
tooltip: '预览',
|
||||
icon: Icons.preview_outlined,
|
||||
onPressed: () async {
|
||||
if (widget.plPlayerController
|
||||
.videoPlayerController !=
|
||||
null) {
|
||||
int start = max(
|
||||
0,
|
||||
(list![index].segment.first * 1000)
|
||||
.toInt() -
|
||||
1,
|
||||
);
|
||||
await widget
|
||||
.plPlayerController.videoPlayerController!
|
||||
.seek(
|
||||
Duration(milliseconds: start),
|
||||
);
|
||||
if (widget
|
||||
.plPlayerController
|
||||
.videoPlayerController!
|
||||
.state
|
||||
.playing
|
||||
.not) {
|
||||
await widget.plPlayerController
|
||||
.videoPlayerController!
|
||||
.play();
|
||||
}
|
||||
if (start != 0) {
|
||||
await Future.delayed(
|
||||
const Duration(seconds: 1));
|
||||
}
|
||||
widget
|
||||
.plPlayerController.videoPlayerController!
|
||||
.seek(
|
||||
Duration(
|
||||
milliseconds:
|
||||
(list![index].segment.second * 1000)
|
||||
.toInt(),
|
||||
),
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.check),
|
||||
SizedBox(
|
||||
height: 88 + MediaQuery.paddingOf(context).bottom,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: errorWidget();
|
||||
Positioned(
|
||||
right: 16,
|
||||
bottom: 16 + MediaQuery.paddingOf(context).bottom,
|
||||
child: FloatingActionButton(
|
||||
tooltip: '提交',
|
||||
onPressed: () {
|
||||
showDialog(
|
||||
context: context,
|
||||
builder: (context) => AlertDialog(
|
||||
title: const Text('确定无误再提交'),
|
||||
actions: [
|
||||
TextButton(
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
onPressed: () {
|
||||
Get.back();
|
||||
_onPost();
|
||||
},
|
||||
child: const Text('确定提交'),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
},
|
||||
child: Icon(Icons.check),
|
||||
),
|
||||
)
|
||||
],
|
||||
)
|
||||
: errorWidget();
|
||||
}
|
||||
|
||||
void updateSegment({
|
||||
required bool isFirst,
|
||||
@@ -413,7 +424,8 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
}
|
||||
}
|
||||
|
||||
List<Widget> segmentWidget({
|
||||
List<Widget> segmentWidget(
|
||||
ThemeData theme, {
|
||||
required int index,
|
||||
required bool isFirst,
|
||||
}) {
|
||||
@@ -484,8 +496,7 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
|
||||
onPressed: Get.back,
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline),
|
||||
style: TextStyle(color: theme.colorScheme.outline),
|
||||
),
|
||||
),
|
||||
TextButton(
|
||||
|
||||
@@ -98,6 +98,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
super.build(context);
|
||||
final theme = Theme.of(context);
|
||||
return refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await _videoReplyController.onRefresh();
|
||||
@@ -120,7 +121,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
floating: true,
|
||||
delegate: CustomSliverPersistentHeaderDelegate(
|
||||
extent: 40,
|
||||
bgColor: Theme.of(context).colorScheme.surface,
|
||||
bgColor: theme.colorScheme.surface,
|
||||
child: Container(
|
||||
height: 40,
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
|
||||
@@ -141,15 +142,14 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
icon: Icon(
|
||||
Icons.sort,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
label: Obx(
|
||||
() => Text(
|
||||
_videoReplyController.sortType.value.label,
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color:
|
||||
Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -160,7 +160,8 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
),
|
||||
),
|
||||
),
|
||||
Obx(() => _buildBody(_videoReplyController.loadingState.value)),
|
||||
Obx(() =>
|
||||
_buildBody(theme, _videoReplyController.loadingState.value)),
|
||||
],
|
||||
),
|
||||
Positioned(
|
||||
@@ -194,7 +195,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState loadingState) {
|
||||
Widget _buildBody(ThemeData theme, LoadingState loadingState) {
|
||||
return switch (loadingState) {
|
||||
Loading() => SliverList.builder(
|
||||
itemBuilder: (BuildContext context, index) {
|
||||
@@ -220,7 +221,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
|
||||
: '没有更多了',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -62,6 +62,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return Material(
|
||||
color: Colors.transparent,
|
||||
child: InkWell(
|
||||
@@ -90,17 +91,17 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
},
|
||||
child: _buildContent(context),
|
||||
child: _buildContent(context, theme),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget _buildAuthorPanel(context) => Padding(
|
||||
Widget _buildAuthorPanel(BuildContext context, ThemeData theme) => Padding(
|
||||
padding: const EdgeInsets.fromLTRB(12, 14, 8, 5),
|
||||
child: content(context),
|
||||
child: content(context, theme),
|
||||
);
|
||||
|
||||
Widget _buildContent(context) {
|
||||
Widget _buildContent(BuildContext context, ThemeData theme) {
|
||||
return Column(
|
||||
children: [
|
||||
if (Avatar.showDynDecorate && replyItem.member.hasGarbCardImage())
|
||||
@@ -138,18 +139,18 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
),
|
||||
SizedBox(
|
||||
width: double.infinity,
|
||||
child: _buildAuthorPanel(context),
|
||||
child: _buildAuthorPanel(context, theme),
|
||||
),
|
||||
],
|
||||
)
|
||||
else
|
||||
_buildAuthorPanel(context),
|
||||
_buildAuthorPanel(context, theme),
|
||||
if (needDivider)
|
||||
Divider(
|
||||
indent: 55,
|
||||
endIndent: 15,
|
||||
height: 0.3,
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.08),
|
||||
color: theme.colorScheme.outline.withOpacity(0.08),
|
||||
)
|
||||
],
|
||||
);
|
||||
@@ -166,7 +167,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
: null,
|
||||
);
|
||||
|
||||
Widget content(BuildContext context) {
|
||||
Widget content(BuildContext context, ThemeData theme) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
@@ -196,7 +197,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
color: (replyItem.member.vipStatus > 0 &&
|
||||
replyItem.member.vipType == 2)
|
||||
? context.vipColor
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
: theme.colorScheme.outline,
|
||||
fontSize: 13,
|
||||
),
|
||||
),
|
||||
@@ -227,20 +228,16 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
.substring(0, 19)
|
||||
: Utils.dateFormat(replyItem.ctime.toInt()),
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelSmall!.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
if (replyItem.replyControl.location.isNotEmpty)
|
||||
Text(
|
||||
' • ${replyItem.replyControl.location}',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.labelSmall!
|
||||
.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline),
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
color: theme.colorScheme.outline),
|
||||
),
|
||||
],
|
||||
)
|
||||
@@ -262,7 +259,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
String text = replyItem.content.message;
|
||||
TextStyle style = TextStyle(
|
||||
height: 1.75,
|
||||
fontSize: Theme.of(context).textTheme.bodyMedium!.fontSize,
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
);
|
||||
TextPainter? textPainter;
|
||||
bool? didExceedMaxLines;
|
||||
@@ -297,8 +294,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
],
|
||||
buildContent(
|
||||
context,
|
||||
theme,
|
||||
replyItem,
|
||||
replyReply,
|
||||
null,
|
||||
textPainter,
|
||||
didExceedMaxLines,
|
||||
@@ -311,16 +308,15 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
),
|
||||
),
|
||||
// 操作区域
|
||||
if (replyLevel != '') buttonAction(context, replyItem.replyControl),
|
||||
if (replyLevel != '')
|
||||
buttonAction(context, theme, replyItem.replyControl),
|
||||
// 一楼的评论
|
||||
if (replyLevel == '1' &&
|
||||
(replyItem.replies.isNotEmpty ||
|
||||
replyItem.replyControl.subReplyEntryText.isNotEmpty)) ...[
|
||||
Padding(
|
||||
padding: const EdgeInsets.only(top: 5, bottom: 12),
|
||||
child: replyItemRow(
|
||||
context: context,
|
||||
),
|
||||
child: replyItemRow(context, theme),
|
||||
),
|
||||
],
|
||||
],
|
||||
@@ -334,7 +330,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
);
|
||||
|
||||
// 感谢、回复、复制
|
||||
Widget buttonAction(BuildContext context, replyControl) {
|
||||
Widget buttonAction(
|
||||
BuildContext context, ThemeData theme, ReplyControl replyControl) {
|
||||
return Row(
|
||||
children: <Widget>[
|
||||
const SizedBox(width: 36),
|
||||
@@ -350,14 +347,14 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
Icon(
|
||||
Icons.reply,
|
||||
size: 18,
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.8),
|
||||
color: theme.colorScheme.outline.withOpacity(0.8),
|
||||
),
|
||||
const SizedBox(width: 3),
|
||||
Text(
|
||||
'回复',
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
]),
|
||||
@@ -373,8 +370,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: Text(
|
||||
'UP主觉得很赞',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
color: theme.colorScheme.secondary,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
@@ -389,8 +386,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
Text(
|
||||
'热评',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize),
|
||||
color: theme.colorScheme.secondary,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize),
|
||||
),
|
||||
if (replyLevel == '2' &&
|
||||
needDivider &&
|
||||
@@ -403,8 +400,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: Text(
|
||||
'查看对话',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
fontSize: Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
color: theme.colorScheme.outline,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
fontWeight: FontWeight.normal,
|
||||
),
|
||||
),
|
||||
@@ -417,12 +414,12 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
Widget replyItemRow({required BuildContext context}) {
|
||||
Widget replyItemRow(BuildContext context, ThemeData theme) {
|
||||
final bool extraRow = replyItem.replies.length < replyItem.count.toInt();
|
||||
return Container(
|
||||
margin: const EdgeInsets.only(left: 42, right: 4, top: 0),
|
||||
child: Material(
|
||||
color: Theme.of(context).colorScheme.onInverseSurface,
|
||||
color: theme.colorScheme.onInverseSurface,
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
clipBehavior: Clip.hardEdge,
|
||||
animationDuration: Duration.zero,
|
||||
@@ -471,14 +468,9 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
excludeSemantics: true,
|
||||
child: Text.rich(
|
||||
style: TextStyle(
|
||||
fontSize: Theme.of(context)
|
||||
.textTheme
|
||||
.bodyMedium!
|
||||
.fontSize,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.85),
|
||||
fontSize: theme.textTheme.bodyMedium!.fontSize,
|
||||
color:
|
||||
theme.colorScheme.onSurface.withOpacity(0.85),
|
||||
height: 1.6),
|
||||
overflow: TextOverflow.ellipsis,
|
||||
maxLines: 2,
|
||||
@@ -487,7 +479,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: replyItem.replies[i].member.name,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -521,8 +513,8 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
),
|
||||
buildContent(
|
||||
context,
|
||||
theme,
|
||||
replyItem.replies[i],
|
||||
replyReply,
|
||||
replyItem,
|
||||
null,
|
||||
null,
|
||||
@@ -544,24 +536,21 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: Text.rich(
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize:
|
||||
Theme.of(context).textTheme.labelMedium!.fontSize,
|
||||
fontSize: theme.textTheme.labelMedium!.fontSize,
|
||||
),
|
||||
children: [
|
||||
if (replyItem.replyControl.upReply)
|
||||
TextSpan(
|
||||
text: 'UP主等人 ',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurface
|
||||
.withOpacity(0.85),
|
||||
color:
|
||||
theme.colorScheme.onSurface.withOpacity(0.85),
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: replyItem.replyControl.subReplyEntryText,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
],
|
||||
@@ -577,11 +566,11 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
|
||||
InlineSpan buildContent(
|
||||
BuildContext context,
|
||||
replyItem,
|
||||
replyReply,
|
||||
fReplyItem,
|
||||
textPainter,
|
||||
didExceedMaxLines,
|
||||
ThemeData theme,
|
||||
ReplyInfo replyItem,
|
||||
ReplyInfo? fReplyItem,
|
||||
TextPainter? textPainter,
|
||||
bool? didExceedMaxLines,
|
||||
) {
|
||||
final String routePath = Get.currentRoute;
|
||||
bool isVideoPage = routePath.startsWith('/video');
|
||||
@@ -594,7 +583,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
final List<InlineSpan> spanChildren = <InlineSpan>[];
|
||||
|
||||
if (didExceedMaxLines == true) {
|
||||
final textSize = textPainter.size;
|
||||
final textSize = textPainter!.size;
|
||||
final double maxHeight = textPainter.preferredLineHeight * 6;
|
||||
var position = textPainter.getPositionForOffset(
|
||||
Offset(textSize.width, maxHeight),
|
||||
@@ -609,7 +598,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: '投票: ${content.vote.title}',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -689,7 +678,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -724,7 +713,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
text: isValid ? ' $matchStr ' : matchStr,
|
||||
style: isValid && isVideoPage
|
||||
? TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
)
|
||||
: null,
|
||||
recognizer: isValid
|
||||
@@ -765,7 +754,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
imageUrl: Utils.thumbnailImgUrl(
|
||||
content.url[matchStr]!.prefixIcon),
|
||||
height: 19,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
placeholder: (context, url) {
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
@@ -775,7 +764,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: content.url[matchStr]!.title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () async {
|
||||
@@ -827,7 +816,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -845,7 +834,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: matchStr,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -885,7 +874,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
imageUrl: Utils.thumbnailImgUrl(
|
||||
content.url[patternStr]!.prefixIcon),
|
||||
height: 19,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
placeholder: (context, url) {
|
||||
return const SizedBox.shrink();
|
||||
},
|
||||
@@ -895,7 +884,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: content.url[patternStr]!.title,
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
@@ -927,7 +916,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: '\n查看更多',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -965,7 +954,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: ' 笔记',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap =
|
||||
@@ -1040,6 +1029,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
bool? isDelete = await showDialog<bool>(
|
||||
context: context,
|
||||
builder: (context) {
|
||||
final theme = Theme.of(context);
|
||||
return AlertDialog(
|
||||
title: const Text('删除评论'),
|
||||
content: Text.rich(
|
||||
@@ -1050,7 +1040,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
TextSpan(
|
||||
text: '@${item.member.name}',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
),
|
||||
TextSpan(text: ':\n'),
|
||||
@@ -1067,7 +1057,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
child: Text(
|
||||
'取消',
|
||||
style: TextStyle(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -1114,7 +1104,9 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
Color errorColor = Theme.of(context).colorScheme.error;
|
||||
final theme = Theme.of(context);
|
||||
Color errorColor = theme.colorScheme.error;
|
||||
final style = theme.textTheme.titleSmall;
|
||||
|
||||
return Padding(
|
||||
padding:
|
||||
@@ -1136,7 +1128,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
width: 32,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3))),
|
||||
),
|
||||
),
|
||||
@@ -1147,48 +1139,42 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
onTap: () => menuActionHandler('delete'),
|
||||
minLeadingWidth: 0,
|
||||
leading: Icon(Icons.delete_outlined, color: errorColor, size: 19),
|
||||
title: Text('删除',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.copyWith(color: errorColor)),
|
||||
title: Text('删除', style: style!.copyWith(color: errorColor)),
|
||||
),
|
||||
if (ownerMid != 0)
|
||||
ListTile(
|
||||
onTap: () => menuActionHandler('report'),
|
||||
minLeadingWidth: 0,
|
||||
leading: Icon(Icons.error_outline, color: errorColor, size: 19),
|
||||
title: Text('举报',
|
||||
style: Theme.of(context)
|
||||
.textTheme
|
||||
.titleSmall!
|
||||
.copyWith(color: errorColor)),
|
||||
title: Text('举报', style: style!.copyWith(color: errorColor)),
|
||||
),
|
||||
if (replyLevel == '1' && isSubReply.not && ownerMid == upMid.toInt())
|
||||
ListTile(
|
||||
onTap: () => menuActionHandler('top'),
|
||||
minLeadingWidth: 0,
|
||||
leading: Icon(Icons.vertical_align_top, size: 19),
|
||||
title: Text('${replyItem.replyControl.isUpTop ? '取消' : ''}置顶',
|
||||
style: Theme.of(context).textTheme.titleSmall!),
|
||||
title: Text(
|
||||
'${replyItem.replyControl.isUpTop ? '取消' : ''}置顶',
|
||||
style: style,
|
||||
),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => menuActionHandler('copyAll'),
|
||||
minLeadingWidth: 0,
|
||||
leading: const Icon(Icons.copy_all_outlined, size: 19),
|
||||
title: Text('复制全部', style: Theme.of(context).textTheme.titleSmall),
|
||||
title: Text('复制全部', style: style),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => menuActionHandler('copyFreedom'),
|
||||
minLeadingWidth: 0,
|
||||
leading: const Icon(Icons.copy_outlined, size: 19),
|
||||
title: Text('自由复制', style: Theme.of(context).textTheme.titleSmall),
|
||||
title: Text('自由复制', style: style),
|
||||
),
|
||||
ListTile(
|
||||
onTap: () => menuActionHandler('saveReply'),
|
||||
minLeadingWidth: 0,
|
||||
leading: const Icon(Icons.save_alt, size: 19),
|
||||
title: Text('保存评论', style: Theme.of(context).textTheme.titleSmall),
|
||||
title: Text('保存评论', style: style),
|
||||
),
|
||||
if (item.mid.toInt() == ownerMid)
|
||||
ListTile(
|
||||
@@ -1201,8 +1187,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
||||
const Icon(Icons.reply, size: 12),
|
||||
],
|
||||
),
|
||||
title:
|
||||
Text('检查评论', style: Theme.of(context).textTheme.titleSmall),
|
||||
title: Text('检查评论', style: style),
|
||||
),
|
||||
],
|
||||
),
|
||||
|
||||
@@ -102,9 +102,9 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData t = Theme.of(context);
|
||||
final Color color = t.colorScheme.outline;
|
||||
final Color primary = t.colorScheme.primary;
|
||||
final ThemeData theme = Theme.of(context);
|
||||
final Color color = theme.colorScheme.outline;
|
||||
final Color primary = theme.colorScheme.primary;
|
||||
return Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
@@ -160,7 +160,7 @@ class _ZanButtonGrpcState extends State<ZanButtonGrpc> {
|
||||
color: widget.replyItem.replyControl.action.toInt() == 1
|
||||
? primary
|
||||
: color,
|
||||
fontSize: t.textTheme.labelSmall!.fontSize,
|
||||
fontSize: theme.textTheme.labelSmall!.fontSize,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -16,6 +16,7 @@ class ToolbarIconButton extends StatelessWidget {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final ThemeData theme = Theme.of(context);
|
||||
return SizedBox(
|
||||
width: 36,
|
||||
height: 36,
|
||||
@@ -23,16 +24,14 @@ class ToolbarIconButton extends StatelessWidget {
|
||||
tooltip: tooltip,
|
||||
onPressed: onPressed,
|
||||
icon: icon,
|
||||
highlightColor: Theme.of(context).colorScheme.secondaryContainer,
|
||||
highlightColor: theme.colorScheme.secondaryContainer,
|
||||
color: selected
|
||||
? Theme.of(context).colorScheme.onSecondaryContainer
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
? theme.colorScheme.onSecondaryContainer
|
||||
: theme.colorScheme.outline,
|
||||
style: ButtonStyle(
|
||||
padding: WidgetStateProperty.all(EdgeInsets.zero),
|
||||
backgroundColor: WidgetStateProperty.resolveWith((states) {
|
||||
return selected
|
||||
? Theme.of(context).colorScheme.secondaryContainer
|
||||
: null;
|
||||
return selected ? theme.colorScheme.secondaryContainer : null;
|
||||
}),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -93,8 +93,8 @@ class _VideoReplyReplyPanelState
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
Widget get _header => firstFloor == null
|
||||
? _sortWidget
|
||||
Widget _header(ThemeData theme) => firstFloor == null
|
||||
? _sortWidget(theme)
|
||||
: ValueListenableBuilder<Iterable<ItemPosition>>(
|
||||
valueListenable: itemPositionsListener.itemPositions,
|
||||
builder: (context, positions, child) {
|
||||
@@ -109,139 +109,144 @@ class _VideoReplyReplyPanelState
|
||||
: min)
|
||||
.index;
|
||||
}
|
||||
return min >= 2 ? _sortWidget : const SizedBox.shrink();
|
||||
return min >= 2 ? _sortWidget(theme) : const SizedBox.shrink();
|
||||
},
|
||||
);
|
||||
|
||||
@override
|
||||
Widget get buildPage => Scaffold(
|
||||
key: _key,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Column(
|
||||
children: [
|
||||
widget.source == 'videoDetail'
|
||||
? Container(
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
width: 1,
|
||||
color:
|
||||
Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
),
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
key: _key,
|
||||
resizeToAvoidBottomInset: false,
|
||||
body: Column(
|
||||
children: [
|
||||
widget.source == 'videoDetail'
|
||||
? Container(
|
||||
height: 45,
|
||||
decoration: BoxDecoration(
|
||||
border: Border(
|
||||
bottom: BorderSide(
|
||||
width: 1,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
padding: const EdgeInsets.only(left: 12, right: 2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(widget.isDialogue ? '对话列表' : '评论详情'),
|
||||
IconButton(
|
||||
tooltip: '关闭',
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
onPressed: Get.back,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
),
|
||||
Expanded(
|
||||
child: enableSlide ? slideList() : buildList,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
padding: const EdgeInsets.only(left: 12, right: 2),
|
||||
child: Row(
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
children: <Widget>[
|
||||
Text(widget.isDialogue ? '对话列表' : '评论详情'),
|
||||
IconButton(
|
||||
tooltip: '关闭',
|
||||
icon: const Icon(Icons.close, size: 20),
|
||||
onPressed: Get.back,
|
||||
),
|
||||
],
|
||||
),
|
||||
)
|
||||
: Divider(
|
||||
height: 1,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
),
|
||||
Expanded(
|
||||
child: enableSlide ? slideList(theme) : buildList(theme),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildList => ClipRect(
|
||||
child: refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await _videoReplyReplyController.onRefresh();
|
||||
},
|
||||
child: Obx(
|
||||
() => Stack(
|
||||
children: [
|
||||
ScrollablePositionedList.builder(
|
||||
key: _listKey,
|
||||
itemPositionsListener: itemPositionsListener,
|
||||
itemCount:
|
||||
_itemCount(_videoReplyReplyController.loadingState.value),
|
||||
itemScrollController:
|
||||
_videoReplyReplyController.itemScrollCtr,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
if (widget.isDialogue) {
|
||||
return _buildBody(
|
||||
_videoReplyReplyController.loadingState.value, index);
|
||||
} else if (firstFloor != null) {
|
||||
if (index == 0) {
|
||||
return ReplyItemGrpc(
|
||||
replyItem: firstFloor,
|
||||
replyLevel: '2',
|
||||
needDivider: false,
|
||||
onReply: () {
|
||||
_onReply(firstFloor, -1);
|
||||
},
|
||||
upMid: _videoReplyReplyController.upMid,
|
||||
onViewImage: widget.onViewImage,
|
||||
onDismissed: widget.onDismissed,
|
||||
callback: _getImageCallback,
|
||||
onCheckReply: (item) => _videoReplyReplyController
|
||||
.onCheckReply(context, item),
|
||||
onToggleTop: (isUpTop, rpid) =>
|
||||
_videoReplyReplyController.onToggleTop(
|
||||
index,
|
||||
_videoReplyReplyController.oid,
|
||||
_videoReplyReplyController.replyType.index,
|
||||
isUpTop,
|
||||
rpid,
|
||||
),
|
||||
);
|
||||
} else if (index == 1) {
|
||||
return Divider(
|
||||
height: 20,
|
||||
color:
|
||||
Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
thickness: 6,
|
||||
);
|
||||
} else if (index == 2) {
|
||||
return _sortWidget;
|
||||
} else {
|
||||
return _buildBody(
|
||||
_videoReplyReplyController.loadingState.value,
|
||||
index - 3);
|
||||
}
|
||||
Widget buildList(ThemeData theme) {
|
||||
return ClipRect(
|
||||
child: refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await _videoReplyReplyController.onRefresh();
|
||||
},
|
||||
child: Obx(
|
||||
() => Stack(
|
||||
children: [
|
||||
ScrollablePositionedList.builder(
|
||||
key: _listKey,
|
||||
itemPositionsListener: itemPositionsListener,
|
||||
itemCount:
|
||||
_itemCount(_videoReplyReplyController.loadingState.value),
|
||||
itemScrollController: _videoReplyReplyController.itemScrollCtr,
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
itemBuilder: (context, index) {
|
||||
if (widget.isDialogue) {
|
||||
return _buildBody(theme,
|
||||
_videoReplyReplyController.loadingState.value, index);
|
||||
} else if (firstFloor != null) {
|
||||
if (index == 0) {
|
||||
return ReplyItemGrpc(
|
||||
replyItem: firstFloor,
|
||||
replyLevel: '2',
|
||||
needDivider: false,
|
||||
onReply: () {
|
||||
_onReply(firstFloor, -1);
|
||||
},
|
||||
upMid: _videoReplyReplyController.upMid,
|
||||
onViewImage: widget.onViewImage,
|
||||
onDismissed: widget.onDismissed,
|
||||
callback: _getImageCallback,
|
||||
onCheckReply: (item) => _videoReplyReplyController
|
||||
.onCheckReply(context, item),
|
||||
onToggleTop: (isUpTop, rpid) =>
|
||||
_videoReplyReplyController.onToggleTop(
|
||||
index,
|
||||
_videoReplyReplyController.oid,
|
||||
_videoReplyReplyController.replyType.index,
|
||||
isUpTop,
|
||||
rpid,
|
||||
),
|
||||
);
|
||||
} else if (index == 1) {
|
||||
return Divider(
|
||||
height: 20,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
thickness: 6,
|
||||
);
|
||||
} else if (index == 2) {
|
||||
return _sortWidget(theme);
|
||||
} else {
|
||||
if (index == 0) {
|
||||
return _sortWidget;
|
||||
} else {
|
||||
return _buildBody(
|
||||
_videoReplyReplyController.loadingState.value,
|
||||
index - 1);
|
||||
}
|
||||
return _buildBody(
|
||||
theme,
|
||||
_videoReplyReplyController.loadingState.value,
|
||||
index - 3,
|
||||
);
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!widget.isDialogue &&
|
||||
_videoReplyReplyController.loadingState.value is Success)
|
||||
_header,
|
||||
],
|
||||
),
|
||||
} else {
|
||||
if (index == 0) {
|
||||
return _sortWidget(theme);
|
||||
} else {
|
||||
return _buildBody(
|
||||
theme,
|
||||
_videoReplyReplyController.loadingState.value,
|
||||
index - 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
),
|
||||
if (!widget.isDialogue &&
|
||||
_videoReplyReplyController.loadingState.value is Success)
|
||||
_header(theme),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _sortWidget => Container(
|
||||
Widget _sortWidget(ThemeData theme) => Container(
|
||||
height: 40,
|
||||
padding: const EdgeInsets.fromLTRB(12, 0, 6, 0),
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
color: theme.colorScheme.surface,
|
||||
boxShadow: [
|
||||
BoxShadow(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
color: theme.colorScheme.surface,
|
||||
offset: const Offset(0, -2),
|
||||
),
|
||||
],
|
||||
@@ -264,7 +269,7 @@ class _VideoReplyReplyPanelState
|
||||
icon: Icon(
|
||||
Icons.sort,
|
||||
size: 16,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
label: Obx(
|
||||
() => Text(
|
||||
@@ -273,7 +278,7 @@ class _VideoReplyReplyPanelState
|
||||
: '按时间',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: Theme.of(context).colorScheme.secondary,
|
||||
color: theme.colorScheme.secondary,
|
||||
),
|
||||
),
|
||||
),
|
||||
@@ -384,7 +389,7 @@ class _VideoReplyReplyPanelState
|
||||
});
|
||||
}
|
||||
|
||||
Widget _buildBody(LoadingState loadingState, int index) {
|
||||
Widget _buildBody(ThemeData theme, LoadingState loadingState, int index) {
|
||||
return switch (loadingState) {
|
||||
Loading() => IgnorePointer(
|
||||
child: CustomScrollView(
|
||||
@@ -416,7 +421,7 @@ class _VideoReplyReplyPanelState
|
||||
: '没有更多了',
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color: Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
);
|
||||
@@ -424,15 +429,15 @@ class _VideoReplyReplyPanelState
|
||||
if (_videoReplyReplyController.index != null &&
|
||||
_videoReplyReplyController.index == index) {
|
||||
colorAnimation ??= ColorTween(
|
||||
begin: Theme.of(context).colorScheme.onInverseSurface,
|
||||
end: Theme.of(context).colorScheme.surface,
|
||||
begin: theme.colorScheme.onInverseSurface,
|
||||
end: theme.colorScheme.surface,
|
||||
).animate(_videoReplyReplyController.controller!);
|
||||
return AnimatedBuilder(
|
||||
animation: colorAnimation!,
|
||||
builder: (context, child) {
|
||||
return ColoredBox(
|
||||
color: colorAnimation!.value ??
|
||||
Theme.of(context).colorScheme.onInverseSurface,
|
||||
theme.colorScheme.onInverseSurface,
|
||||
child: _replyItem(loadingState.response[index], index),
|
||||
);
|
||||
},
|
||||
|
||||
@@ -33,136 +33,134 @@ class _ViewPointsPageState
|
||||
int currentIndex = -1;
|
||||
|
||||
@override
|
||||
Widget get buildPage => Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('分段信息'),
|
||||
toolbarHeight: 45,
|
||||
actions: [
|
||||
Text(
|
||||
'分段进度条',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
Obx(
|
||||
() => Transform.scale(
|
||||
alignment: Alignment.centerLeft,
|
||||
scale: 0.8,
|
||||
child: Switch(
|
||||
thumbIcon: WidgetStateProperty.resolveWith<Icon?>((states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.done);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
value: videoDetailController.plPlayerController.showVP.value,
|
||||
onChanged: (value) {
|
||||
videoDetailController.plPlayerController.showVP.value =
|
||||
value;
|
||||
},
|
||||
),
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Scaffold(
|
||||
resizeToAvoidBottomInset: false,
|
||||
appBar: AppBar(
|
||||
automaticallyImplyLeading: false,
|
||||
titleSpacing: 16,
|
||||
title: const Text('分段信息'),
|
||||
toolbarHeight: 45,
|
||||
actions: [
|
||||
Text(
|
||||
'分段进度条',
|
||||
style: TextStyle(fontSize: 16),
|
||||
),
|
||||
Obx(
|
||||
() => Transform.scale(
|
||||
alignment: Alignment.centerLeft,
|
||||
scale: 0.8,
|
||||
child: Switch(
|
||||
thumbIcon: WidgetStateProperty.resolveWith<Icon?>((states) {
|
||||
if (states.isNotEmpty &&
|
||||
states.first == WidgetState.selected) {
|
||||
return const Icon(Icons.done);
|
||||
}
|
||||
return null;
|
||||
}),
|
||||
value: videoDetailController.plPlayerController.showVP.value,
|
||||
onChanged: (value) {
|
||||
videoDetailController.plPlayerController.showVP.value = value;
|
||||
},
|
||||
),
|
||||
),
|
||||
iconButton(
|
||||
context: context,
|
||||
size: 30,
|
||||
icon: Icons.clear,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(1),
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
iconButton(
|
||||
context: context,
|
||||
size: 30,
|
||||
icon: Icons.clear,
|
||||
tooltip: '关闭',
|
||||
onPressed: Get.back,
|
||||
),
|
||||
const SizedBox(width: 16),
|
||||
],
|
||||
bottom: PreferredSize(
|
||||
preferredSize: Size.fromHeight(1),
|
||||
child: Divider(
|
||||
height: 1,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
),
|
||||
),
|
||||
body: enableSlide ? slideList() : buildList,
|
||||
);
|
||||
),
|
||||
body: enableSlide ? slideList(theme) : buildList(theme),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildList => ListView.separated(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding:
|
||||
EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
itemCount: videoDetailController.viewPointList.length,
|
||||
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!) {
|
||||
currentIndex = index;
|
||||
}
|
||||
Widget buildList(ThemeData theme) {
|
||||
return ListView.separated(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
padding:
|
||||
EdgeInsets.only(bottom: MediaQuery.paddingOf(context).bottom + 80),
|
||||
itemCount: videoDetailController.viewPointList.length,
|
||||
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!) {
|
||||
currentIndex = index;
|
||||
}
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: segment.from != null
|
||||
? () {
|
||||
currentIndex = index;
|
||||
plPlayerController?.danmakuController?.clear();
|
||||
plPlayerController?.videoPlayerController
|
||||
?.seek(Duration(seconds: segment.from!));
|
||||
Get.back();
|
||||
}
|
||||
: null,
|
||||
leading: segment.url?.isNotEmpty == true
|
||||
? Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: currentIndex == index
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
width: 1.8,
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => NetworkImgLayer(
|
||||
radius: 6,
|
||||
src: segment.url,
|
||||
width: constraints.maxHeight * StyleString.aspectRatio,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
}
|
||||
return ListTile(
|
||||
dense: true,
|
||||
onTap: segment.from != null
|
||||
? () {
|
||||
currentIndex = index;
|
||||
plPlayerController?.danmakuController?.clear();
|
||||
plPlayerController?.videoPlayerController
|
||||
?.seek(Duration(seconds: segment.from!));
|
||||
Get.back();
|
||||
}
|
||||
: null,
|
||||
leading: segment.url?.isNotEmpty == true
|
||||
? Container(
|
||||
margin: const EdgeInsets.symmetric(vertical: 6),
|
||||
decoration: currentIndex == index
|
||||
? BoxDecoration(
|
||||
borderRadius: BorderRadius.circular(6),
|
||||
border: Border.all(
|
||||
width: 1.8,
|
||||
strokeAlign: BorderSide.strokeAlignOutside,
|
||||
color: theme.colorScheme.primary,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
child: LayoutBuilder(
|
||||
builder: (context, constraints) => NetworkImgLayer(
|
||||
radius: 6,
|
||||
src: segment.url,
|
||||
width: constraints.maxHeight * StyleString.aspectRatio,
|
||||
height: constraints.maxHeight,
|
||||
),
|
||||
)
|
||||
: null,
|
||||
title: Text(
|
||||
segment.title ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: currentIndex == index ? FontWeight.bold : null,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
)
|
||||
: null,
|
||||
title: Text(
|
||||
segment.title ?? '',
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: currentIndex == index ? FontWeight.bold : null,
|
||||
color: currentIndex == index ? theme.colorScheme.primary : null,
|
||||
),
|
||||
subtitle: Text(
|
||||
'${segment.from != null ? Utils.timeFormat(segment.from) : ''} - ${segment.to != null ? Utils.timeFormat(segment.to) : ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: currentIndex == index
|
||||
? Theme.of(context).colorScheme.primary
|
||||
: Theme.of(context).colorScheme.outline,
|
||||
),
|
||||
),
|
||||
subtitle: Text(
|
||||
'${segment.from != null ? Utils.timeFormat(segment.from) : ''} - ${segment.to != null ? Utils.timeFormat(segment.to) : ''}',
|
||||
style: TextStyle(
|
||||
fontSize: 13,
|
||||
color: currentIndex == index
|
||||
? theme.colorScheme.primary
|
||||
: theme.colorScheme.outline,
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
),
|
||||
);
|
||||
),
|
||||
);
|
||||
},
|
||||
separatorBuilder: (context, index) => Divider(
|
||||
height: 1,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
import 'package:PiliPlus/common/constants.dart';
|
||||
import 'package:PiliPlus/pages/common/common_collapse_slide_page.dart';
|
||||
import 'package:PiliPlus/pages/video/detail/controller.dart';
|
||||
import 'package:PiliPlus/utils/page_utils.dart';
|
||||
import 'package:flutter/gestures.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||
import 'package:get/get.dart';
|
||||
import 'package:PiliPlus/models/video/ai.dart';
|
||||
import 'package:PiliPlus/utils/utils.dart';
|
||||
@@ -22,199 +19,133 @@ class AiDetail extends CommonCollapseSlidePage {
|
||||
}
|
||||
|
||||
class _AiDetailState extends CommonCollapseSlidePageState<AiDetail> {
|
||||
InlineSpan buildContent(BuildContext context, content) {
|
||||
List descV2 = content.descV2;
|
||||
// type
|
||||
// 1 普通文本
|
||||
// 2 @用户
|
||||
List<TextSpan> spanChildren = List.generate(descV2.length, (index) {
|
||||
final currentDesc = descV2[index];
|
||||
switch (currentDesc.type) {
|
||||
case 1:
|
||||
List<InlineSpan> spanChildren = [];
|
||||
RegExp urlRegExp = RegExp(Constants.urlPattern);
|
||||
Iterable<Match> matches = urlRegExp.allMatches(currentDesc.rawText);
|
||||
|
||||
int previousEndIndex = 0;
|
||||
for (Match match in matches) {
|
||||
if (match.start > previousEndIndex) {
|
||||
spanChildren.add(TextSpan(
|
||||
text: currentDesc.rawText
|
||||
.substring(previousEndIndex, match.start)));
|
||||
}
|
||||
spanChildren.add(
|
||||
TextSpan(
|
||||
text: match.group(0),
|
||||
style: TextStyle(color: Theme.of(context).colorScheme.primary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
try {
|
||||
PageUtils.handleWebview(match.group(0)!);
|
||||
} catch (err) {
|
||||
SmartDialog.showToast(err.toString());
|
||||
}
|
||||
},
|
||||
@override
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Material(
|
||||
color: theme.colorScheme.surface,
|
||||
child: Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: Get.back,
|
||||
child: Container(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: theme.colorScheme.primary,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3)),
|
||||
),
|
||||
),
|
||||
),
|
||||
);
|
||||
previousEndIndex = match.end;
|
||||
}
|
||||
|
||||
if (previousEndIndex < currentDesc.rawText.length) {
|
||||
spanChildren.add(TextSpan(
|
||||
text: currentDesc.rawText.substring(previousEndIndex)));
|
||||
}
|
||||
|
||||
TextSpan result = TextSpan(children: spanChildren);
|
||||
return result;
|
||||
case 2:
|
||||
final colorSchemePrimary = Theme.of(context).colorScheme.primary;
|
||||
final heroTag = Utils.makeHeroTag(currentDesc.bizId);
|
||||
return TextSpan(
|
||||
text: '@${currentDesc.rawText}',
|
||||
style: TextStyle(color: colorSchemePrimary),
|
||||
recognizer: TapGestureRecognizer()
|
||||
..onTap = () {
|
||||
Get.toNamed(
|
||||
'/member?mid=${currentDesc.bizId}',
|
||||
arguments: {'face': '', 'heroTag': heroTag},
|
||||
);
|
||||
},
|
||||
);
|
||||
default:
|
||||
return const TextSpan();
|
||||
}
|
||||
});
|
||||
return TextSpan(children: spanChildren);
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: enableSlide ? slideList(theme) : buildList(theme),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildPage => Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
child: Column(
|
||||
children: [
|
||||
GestureDetector(
|
||||
onTap: Get.back,
|
||||
child: Container(
|
||||
height: 35,
|
||||
padding: const EdgeInsets.only(bottom: 2),
|
||||
child: Center(
|
||||
child: Container(
|
||||
width: 32,
|
||||
height: 3,
|
||||
decoration: BoxDecoration(
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
borderRadius: const BorderRadius.all(Radius.circular(3)),
|
||||
),
|
||||
),
|
||||
Widget buildList(ThemeData theme) {
|
||||
return CustomScrollView(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
if (widget.modelResult.summary?.isNotEmpty == true) ...[
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: SelectableText(
|
||||
widget.modelResult.summary!,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: enableSlide ? slideList() : buildList,
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget get buildList => CustomScrollView(
|
||||
controller: ScrollController(),
|
||||
physics: const AlwaysScrollableScrollPhysics(),
|
||||
slivers: [
|
||||
if (widget.modelResult.summary?.isNotEmpty == true) ...[
|
||||
SliverToBoxAdapter(
|
||||
child: Padding(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 14),
|
||||
child: SelectableText(
|
||||
widget.modelResult.summary!,
|
||||
style: const TextStyle(
|
||||
fontSize: 15,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
),
|
||||
),
|
||||
if (widget.modelResult.outline?.isNotEmpty == true)
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(
|
||||
height: 20,
|
||||
color: Theme.of(context).dividerColor.withOpacity(0.1),
|
||||
thickness: 6,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
if (widget.modelResult.outline?.isNotEmpty == true)
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 14,
|
||||
right: 14,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverList.builder(
|
||||
itemCount: widget.modelResult.outline!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (index != 0) const SizedBox(height: 10),
|
||||
SelectableText(
|
||||
widget.modelResult.outline![index].title!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (widget.modelResult.outline![index].partOutline
|
||||
?.isNotEmpty ==
|
||||
true)
|
||||
...widget.modelResult.outline![index].partOutline!.map(
|
||||
(item) => Wrap(
|
||||
children: [
|
||||
SelectableText.rich(
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color:
|
||||
Theme.of(context).colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text:
|
||||
Utils.formatDuration(item.timestamp!),
|
||||
style: TextStyle(
|
||||
color: Theme.of(context)
|
||||
.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!),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
SliverToBoxAdapter(
|
||||
child: Divider(
|
||||
height: 20,
|
||||
color: theme.dividerColor.withOpacity(0.1),
|
||||
thickness: 6,
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
if (widget.modelResult.outline?.isNotEmpty == true)
|
||||
SliverPadding(
|
||||
padding: EdgeInsets.only(
|
||||
left: 14,
|
||||
right: 14,
|
||||
bottom: MediaQuery.paddingOf(context).bottom + 80,
|
||||
),
|
||||
sliver: SliverList.builder(
|
||||
itemCount: widget.modelResult.outline!.length,
|
||||
itemBuilder: (context, index) {
|
||||
return Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
if (index != 0) const SizedBox(height: 10),
|
||||
SelectableText(
|
||||
widget.modelResult.outline![index].title!,
|
||||
style: const TextStyle(
|
||||
fontSize: 14,
|
||||
fontWeight: FontWeight.bold,
|
||||
height: 1.5,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 6),
|
||||
if (widget.modelResult.outline![index].partOutline
|
||||
?.isNotEmpty ==
|
||||
true)
|
||||
...widget.modelResult.outline![index].partOutline!.map(
|
||||
(item) => Wrap(
|
||||
children: [
|
||||
SelectableText.rich(
|
||||
TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: 14,
|
||||
color: theme.colorScheme.onSurface,
|
||||
height: 1.5,
|
||||
),
|
||||
children: [
|
||||
TextSpan(
|
||||
text: Utils.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!),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -78,9 +78,9 @@ class _MediaListPanelState
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildPage {
|
||||
Widget buildPage(ThemeData theme) {
|
||||
return Material(
|
||||
color: Theme.of(context).colorScheme.surface,
|
||||
color: theme.colorScheme.surface,
|
||||
child: Column(
|
||||
children: [
|
||||
AppBar(
|
||||
@@ -111,10 +111,10 @@ class _MediaListPanelState
|
||||
),
|
||||
Divider(
|
||||
height: 1,
|
||||
color: Theme.of(context).colorScheme.outline.withOpacity(0.1),
|
||||
color: theme.colorScheme.outline.withOpacity(0.1),
|
||||
),
|
||||
Expanded(
|
||||
child: enableSlide ? slideList() : buildList,
|
||||
child: enableSlide ? slideList(theme) : buildList(theme),
|
||||
),
|
||||
],
|
||||
),
|
||||
@@ -122,16 +122,18 @@ class _MediaListPanelState
|
||||
}
|
||||
|
||||
@override
|
||||
Widget get buildList => widget.loadPrevious != null
|
||||
? refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.loadPrevious!();
|
||||
},
|
||||
child: _buildList,
|
||||
)
|
||||
: _buildList;
|
||||
Widget buildList(ThemeData theme) {
|
||||
return widget.loadPrevious != null
|
||||
? refreshIndicator(
|
||||
onRefresh: () async {
|
||||
await widget.loadPrevious!();
|
||||
},
|
||||
child: _buildList(theme),
|
||||
)
|
||||
: _buildList(theme);
|
||||
}
|
||||
|
||||
Widget get _buildList => Obx(
|
||||
Widget _buildList(ThemeData theme) => Obx(
|
||||
() {
|
||||
final showDelBtn =
|
||||
widget.onDelete != null && widget.mediaList.length > 1;
|
||||
@@ -172,7 +174,6 @@ class _MediaListPanelState
|
||||
},
|
||||
onLongPress: () {
|
||||
imageSaveDialog(
|
||||
context: context,
|
||||
title: item.title,
|
||||
cover: item.cover,
|
||||
);
|
||||
@@ -225,9 +226,7 @@ class _MediaListPanelState
|
||||
? FontWeight.bold
|
||||
: null,
|
||||
color: item.bvid == widget.getBvId()
|
||||
? Theme.of(context)
|
||||
.colorScheme
|
||||
.primary
|
||||
? theme.colorScheme.primary
|
||||
: null,
|
||||
),
|
||||
),
|
||||
@@ -236,8 +235,7 @@ class _MediaListPanelState
|
||||
item.upper!.name!,
|
||||
style: TextStyle(
|
||||
fontSize: 12,
|
||||
color:
|
||||
Theme.of(context).colorScheme.outline,
|
||||
color: theme.colorScheme.outline,
|
||||
),
|
||||
),
|
||||
const SizedBox(height: 3),
|
||||
@@ -283,9 +281,7 @@ class _MediaListPanelState
|
||||
child: Icon(
|
||||
Icons.clear,
|
||||
size: 18,
|
||||
color: Theme.of(context)
|
||||
.colorScheme
|
||||
.onSurfaceVariant,
|
||||
color: theme.colorScheme.onSurfaceVariant,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
Reference in New Issue
Block a user