mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-08-04 17:50:13 +08:00
@@ -32,7 +32,8 @@ class DownloadSearchController
|
|||||||
.where(
|
.where(
|
||||||
(e) =>
|
(e) =>
|
||||||
e.title.toLowerCase().contains(text) ||
|
e.title.toLowerCase().contains(text) ||
|
||||||
e.showTitle.toLowerCase().contains(text),
|
e.showTitle.toLowerCase().contains(text) ||
|
||||||
|
(e.ownerName?.toLowerCase().contains(text) ?? false),
|
||||||
)
|
)
|
||||||
.toList(),
|
.toList(),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -395,6 +395,7 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Column _buildRight(ColorScheme colorScheme) => Column(
|
Column _buildRight(ColorScheme colorScheme) => Column(
|
||||||
|
spacing: 5,
|
||||||
mainAxisSize: .min,
|
mainAxisSize: .min,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
@@ -418,7 +419,6 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
.skip(1)
|
.skip(1)
|
||||||
.toList(),
|
.toList(),
|
||||||
),
|
),
|
||||||
const SizedBox(height: 5),
|
|
||||||
Row(
|
Row(
|
||||||
spacing: 10,
|
spacing: 10,
|
||||||
mainAxisSize: .min,
|
mainAxisSize: .min,
|
||||||
@@ -441,22 +441,25 @@ class UserInfoCard extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
icon: const Icon(Icons.mail_outline, size: 21),
|
icon: const Icon(Icons.mail_outline, size: 21),
|
||||||
style: IconButton.styleFrom(
|
style: ButtonStyle(
|
||||||
side: BorderSide(
|
side: WidgetStatePropertyAll(
|
||||||
width: 1.0,
|
BorderSide(
|
||||||
color: colorScheme.outline.withValues(alpha: 0.3),
|
width: 1.0,
|
||||||
|
color: colorScheme.outline.withValues(alpha: 0.3),
|
||||||
|
),
|
||||||
),
|
),
|
||||||
padding: .zero,
|
padding: const WidgetStatePropertyAll(.zero),
|
||||||
tapTargetSize: .padded,
|
tapTargetSize: .shrinkWrap,
|
||||||
visualDensity: .compact,
|
visualDensity: .compact,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
Expanded(
|
Expanded(
|
||||||
child: FilledButton.tonal(
|
child: FilledButton.tonal(
|
||||||
onPressed: !isOwner && relation == -1 ? null : onFollow,
|
onPressed: !isOwner && relation == -1 ? null : onFollow,
|
||||||
style: FilledButton.styleFrom(
|
style: ButtonStyle(
|
||||||
|
padding: const WidgetStatePropertyAll(.zero),
|
||||||
backgroundColor: relation != 0
|
backgroundColor: relation != 0
|
||||||
? colorScheme.onInverseSurface
|
? WidgetStatePropertyAll(colorScheme.onInverseSurface)
|
||||||
: null,
|
: null,
|
||||||
tapTargetSize: .padded,
|
tapTargetSize: .padded,
|
||||||
visualDensity: const VisualDensity(vertical: -1.8),
|
visualDensity: const VisualDensity(vertical: -1.8),
|
||||||
|
|||||||
@@ -21,7 +21,6 @@ import 'package:PiliPlus/grpc/reply.dart';
|
|||||||
import 'package:PiliPlus/http/loading_state.dart';
|
import 'package:PiliPlus/http/loading_state.dart';
|
||||||
import 'package:PiliPlus/http/reply.dart';
|
import 'package:PiliPlus/http/reply.dart';
|
||||||
import 'package:PiliPlus/http/video.dart';
|
import 'package:PiliPlus/http/video.dart';
|
||||||
import 'package:PiliPlus/models/common/badge_type.dart';
|
|
||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
|
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
|
||||||
import 'package:PiliPlus/pages/member/widget/medal_widget.dart';
|
import 'package:PiliPlus/pages/member/widget/medal_widget.dart';
|
||||||
@@ -33,6 +32,7 @@ import 'package:PiliPlus/utils/app_scheme.dart';
|
|||||||
import 'package:PiliPlus/utils/bili_utils.dart';
|
import 'package:PiliPlus/utils/bili_utils.dart';
|
||||||
import 'package:PiliPlus/utils/color_utils.dart';
|
import 'package:PiliPlus/utils/color_utils.dart';
|
||||||
import 'package:PiliPlus/utils/danmaku_utils.dart';
|
import 'package:PiliPlus/utils/danmaku_utils.dart';
|
||||||
|
import 'package:PiliPlus/utils/date_utils.dart';
|
||||||
import 'package:PiliPlus/utils/duration_utils.dart';
|
import 'package:PiliPlus/utils/duration_utils.dart';
|
||||||
import 'package:PiliPlus/utils/extension/context_ext.dart';
|
import 'package:PiliPlus/utils/extension/context_ext.dart';
|
||||||
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
import 'package:PiliPlus/utils/extension/iterable_ext.dart';
|
||||||
@@ -167,13 +167,14 @@ class ReplyItemGrpc extends StatelessWidget {
|
|||||||
? member.garbPendantImage
|
? member.garbPendantImage
|
||||||
: null,
|
: null,
|
||||||
),
|
),
|
||||||
Expanded(
|
Flexible(
|
||||||
child: Column(
|
child: Column(
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
mainAxisSize: .min,
|
||||||
mainAxisSize: MainAxisSize.min,
|
crossAxisAlignment: .start,
|
||||||
children: [
|
children: [
|
||||||
Row(
|
Row(
|
||||||
spacing: 6,
|
spacing: 6,
|
||||||
|
mainAxisSize: .min,
|
||||||
children: [
|
children: [
|
||||||
Flexible(
|
Flexible(
|
||||||
child: Text(
|
child: Text(
|
||||||
@@ -196,7 +197,7 @@ class ReplyItemGrpc extends StatelessWidget {
|
|||||||
if (replyItem.mid == upMid)
|
if (replyItem.mid == upMid)
|
||||||
const PBadge(
|
const PBadge(
|
||||||
text: 'UP',
|
text: 'UP',
|
||||||
size: PBadgeSize.small,
|
size: .small,
|
||||||
isStack: false,
|
isStack: false,
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
)
|
)
|
||||||
@@ -211,23 +212,33 @@ class ReplyItemGrpc extends StatelessWidget {
|
|||||||
nameColor: DmUtils.decimalToColor(
|
nameColor: DmUtils.decimalToColor(
|
||||||
member.fansMedalColorName.toInt(),
|
member.fansMedalColorName.toInt(),
|
||||||
),
|
),
|
||||||
padding: const .symmetric(
|
padding: const .symmetric(horizontal: 6, vertical: 1.5),
|
||||||
horizontal: 6,
|
|
||||||
vertical: 1.5,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
Row(
|
Row(
|
||||||
mainAxisSize: MainAxisSize.min,
|
mainAxisSize: .min,
|
||||||
children: [
|
children: [
|
||||||
Text(
|
Text(
|
||||||
' • ${replyItem.replyControl.location}',
|
replyLevel == 0
|
||||||
|
? DateFormatUtils.format(
|
||||||
|
replyItem.ctime.toInt(),
|
||||||
|
format: DateFormatUtils.longFormatDs,
|
||||||
|
)
|
||||||
|
: DateFormatUtils.dateFormat(replyItem.ctime.toInt()),
|
||||||
style: TextStyle(
|
style: TextStyle(
|
||||||
fontSize: 11,
|
fontSize: 11,
|
||||||
color: colorScheme.outline,
|
color: colorScheme.outline,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
if (replyItem.replyControl.hasLocation())
|
||||||
|
Text(
|
||||||
|
' • ${replyItem.replyControl.location}',
|
||||||
|
style: TextStyle(
|
||||||
|
fontSize: 11,
|
||||||
|
color: colorScheme.outline,
|
||||||
|
),
|
||||||
|
),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
],
|
],
|
||||||
@@ -337,12 +348,12 @@ class ReplyItemGrpc extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
if (replyControl.isUpTop) ...[
|
if (replyControl.isUpTop) ...[
|
||||||
const WidgetSpan(
|
const WidgetSpan(
|
||||||
alignment: PlaceholderAlignment.middle,
|
alignment: .middle,
|
||||||
child: PBadge(
|
child: PBadge(
|
||||||
text: 'TOP',
|
text: 'TOP',
|
||||||
size: PBadgeSize.small,
|
size: .small,
|
||||||
isStack: false,
|
isStack: false,
|
||||||
type: PBadgeType.line_primary,
|
type: .line_primary,
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
textScaleFactor: 1,
|
textScaleFactor: 1,
|
||||||
),
|
),
|
||||||
@@ -628,10 +639,10 @@ class ReplyItemGrpc extends StatelessWidget {
|
|||||||
if (childReply.mid == upMid) ...[
|
if (childReply.mid == upMid) ...[
|
||||||
const TextSpan(text: ' '),
|
const TextSpan(text: ' '),
|
||||||
const WidgetSpan(
|
const WidgetSpan(
|
||||||
alignment: PlaceholderAlignment.middle,
|
alignment: .middle,
|
||||||
child: PBadge(
|
child: PBadge(
|
||||||
text: 'UP',
|
text: 'UP',
|
||||||
size: PBadgeSize.small,
|
size: .small,
|
||||||
isStack: false,
|
isStack: false,
|
||||||
fontSize: 9,
|
fontSize: 9,
|
||||||
textScaleFactor: 1,
|
textScaleFactor: 1,
|
||||||
|
|||||||
@@ -24,22 +24,17 @@ mixin HeaderMixin<T extends StatefulWidget> on State<T> {
|
|||||||
StatefulWidgetBuilder builder, {
|
StatefulWidgetBuilder builder, {
|
||||||
ValueGetter<EdgeInsets>? padding,
|
ValueGetter<EdgeInsets>? padding,
|
||||||
}) {
|
}) {
|
||||||
|
final theme = this.theme;
|
||||||
return PageUtils.showVideoBottomSheet(
|
return PageUtils.showVideoBottomSheet(
|
||||||
context,
|
context,
|
||||||
maxWidth: 512,
|
maxWidth: 512,
|
||||||
padding: padding,
|
padding: padding,
|
||||||
child: StatefulBuilder(
|
child: theme != null
|
||||||
builder: (context, setState) {
|
? Theme(
|
||||||
final theme = this.theme;
|
|
||||||
if (theme != null) {
|
|
||||||
return Theme(
|
|
||||||
data: theme,
|
data: theme,
|
||||||
child: builder(this.context, setState),
|
child: StatefulBuilder(builder: builder),
|
||||||
);
|
)
|
||||||
}
|
: StatefulBuilder(builder: builder),
|
||||||
return builder(context, setState);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import 'package:PiliPlus/pages/video/introduction/ugc/widgets/menu_row.dart';
|
|||||||
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
import 'package:PiliPlus/plugin/pl_player/controller.dart';
|
||||||
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
import 'package:PiliPlus/plugin/pl_player/models/play_status.dart';
|
||||||
import 'package:PiliPlus/utils/page_utils.dart';
|
import 'package:PiliPlus/utils/page_utils.dart';
|
||||||
|
import 'package:PiliPlus/utils/theme_utils.dart';
|
||||||
import 'package:collection/collection.dart';
|
import 'package:collection/collection.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
import 'package:flutter_smart_dialog/flutter_smart_dialog.dart';
|
||||||
@@ -145,130 +146,130 @@ class ShutdownTimerService {
|
|||||||
if (isLive) {
|
if (isLive) {
|
||||||
_waitUntilCompleted = false;
|
_waitUntilCompleted = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
final child = StatefulBuilder(
|
||||||
|
builder: (context, setState) {
|
||||||
|
final ThemeData theme = Theme.of(context);
|
||||||
|
return Padding(
|
||||||
|
padding: const .all(12),
|
||||||
|
child: Material(
|
||||||
|
clipBehavior: .hardEdge,
|
||||||
|
color: theme.colorScheme.surface,
|
||||||
|
borderRadius: const .all(.circular(12)),
|
||||||
|
child: ListView(
|
||||||
|
padding: const .symmetric(vertical: 14),
|
||||||
|
children: [
|
||||||
|
const Center(child: Text('定时关闭', style: titleStyle)),
|
||||||
|
const SizedBox(height: 10),
|
||||||
|
...{...scheduleTimeMinutes, _durationInMinutes}
|
||||||
|
.sorted(Comparable.compare)
|
||||||
|
.map(
|
||||||
|
(minutes) => ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () {
|
||||||
|
Navigator.pop(context);
|
||||||
|
_startShutdownTimer(minutes);
|
||||||
|
},
|
||||||
|
title: Text(
|
||||||
|
switch (minutes) {
|
||||||
|
0 => '禁用',
|
||||||
|
_ => _format(minutes),
|
||||||
|
},
|
||||||
|
style: titleStyle,
|
||||||
|
),
|
||||||
|
trailing: _durationInMinutes == minutes
|
||||||
|
? Icon(
|
||||||
|
size: 20,
|
||||||
|
Icons.done,
|
||||||
|
color: theme.colorScheme.primary,
|
||||||
|
)
|
||||||
|
: null,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: () {
|
||||||
|
final (int hour, int minute) = _parseMinutes(
|
||||||
|
_durationInMinutes,
|
||||||
|
);
|
||||||
|
showTimePicker(
|
||||||
|
context: context,
|
||||||
|
initialEntryMode: .inputOnly,
|
||||||
|
initialTime: TimeOfDay(hour: hour, minute: minute),
|
||||||
|
builder: (context, child) => MediaQuery(
|
||||||
|
data: MediaQuery.of(
|
||||||
|
context,
|
||||||
|
).copyWith(alwaysUse24HourFormat: true),
|
||||||
|
child: child!,
|
||||||
|
),
|
||||||
|
).then((time) {
|
||||||
|
if (time != null) {
|
||||||
|
_startShutdownTimer(time.hour * 60 + time.minute);
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
title: const Text('自定义', style: titleStyle),
|
||||||
|
),
|
||||||
|
if (!isLive) ...[
|
||||||
|
Builder(
|
||||||
|
builder: (context) {
|
||||||
|
void onChanged([_]) {
|
||||||
|
_waitUntilCompleted = !_waitUntilCompleted;
|
||||||
|
(context as Element).markNeedsBuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
return ListTile(
|
||||||
|
dense: true,
|
||||||
|
onTap: onChanged,
|
||||||
|
title: const Text('额外等待视频播放完毕', style: titleStyle),
|
||||||
|
trailing: Transform.scale(
|
||||||
|
alignment: Alignment.centerRight,
|
||||||
|
scale: 0.8,
|
||||||
|
child: Switch(
|
||||||
|
value: _waitUntilCompleted,
|
||||||
|
onChanged: onChanged,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
],
|
||||||
|
const SizedBox(height: 5),
|
||||||
|
Padding(
|
||||||
|
padding: const .only(left: 18),
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) {
|
||||||
|
return Row(
|
||||||
|
spacing: 12,
|
||||||
|
children: [
|
||||||
|
const Text('倒计时结束:', style: titleStyle),
|
||||||
|
..._ShutdownType.values.map(
|
||||||
|
(e) => ActionRowLineItem(
|
||||||
|
onTap: () {
|
||||||
|
_shutdownType = e;
|
||||||
|
(context as Element).markNeedsBuild();
|
||||||
|
},
|
||||||
|
text: ' ${e.label} ',
|
||||||
|
selectStatus: _shutdownType == e,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
PageUtils.showVideoBottomSheet(
|
PageUtils.showVideoBottomSheet(
|
||||||
context,
|
context,
|
||||||
maxWidth: 512,
|
maxWidth: 512,
|
||||||
child: StatefulBuilder(
|
child: isLive ? Theme(data: ThemeUtils.darkTheme, child: child) : child,
|
||||||
builder: (_, setState) {
|
|
||||||
final ThemeData theme = Theme.of(context);
|
|
||||||
return Theme(
|
|
||||||
data: theme,
|
|
||||||
child: Padding(
|
|
||||||
padding: const .all(12),
|
|
||||||
child: Material(
|
|
||||||
clipBehavior: .hardEdge,
|
|
||||||
color: theme.colorScheme.surface,
|
|
||||||
borderRadius: const .all(.circular(12)),
|
|
||||||
child: ListView(
|
|
||||||
padding: const .symmetric(vertical: 14),
|
|
||||||
children: [
|
|
||||||
const Center(child: Text('定时关闭', style: titleStyle)),
|
|
||||||
const SizedBox(height: 10),
|
|
||||||
...{...scheduleTimeMinutes, _durationInMinutes}
|
|
||||||
.sorted(Comparable.compare)
|
|
||||||
.map(
|
|
||||||
(minutes) => ListTile(
|
|
||||||
dense: true,
|
|
||||||
onTap: () {
|
|
||||||
Navigator.pop(context);
|
|
||||||
_startShutdownTimer(minutes);
|
|
||||||
},
|
|
||||||
title: Text(
|
|
||||||
switch (minutes) {
|
|
||||||
0 => '禁用',
|
|
||||||
_ => _format(minutes),
|
|
||||||
},
|
|
||||||
style: titleStyle,
|
|
||||||
),
|
|
||||||
trailing: _durationInMinutes == minutes
|
|
||||||
? Icon(
|
|
||||||
size: 20,
|
|
||||||
Icons.done,
|
|
||||||
color: theme.colorScheme.primary,
|
|
||||||
)
|
|
||||||
: null,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
ListTile(
|
|
||||||
dense: true,
|
|
||||||
onTap: () {
|
|
||||||
final (int hour, int minute) = _parseMinutes(
|
|
||||||
_durationInMinutes,
|
|
||||||
);
|
|
||||||
showTimePicker(
|
|
||||||
context: context,
|
|
||||||
initialEntryMode: .inputOnly,
|
|
||||||
initialTime: TimeOfDay(hour: hour, minute: minute),
|
|
||||||
builder: (context, child) => MediaQuery(
|
|
||||||
data: MediaQuery.of(
|
|
||||||
context,
|
|
||||||
).copyWith(alwaysUse24HourFormat: true),
|
|
||||||
child: child!,
|
|
||||||
),
|
|
||||||
).then((time) {
|
|
||||||
if (time != null) {
|
|
||||||
_startShutdownTimer(time.hour * 60 + time.minute);
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
title: const Text('自定义', style: titleStyle),
|
|
||||||
),
|
|
||||||
if (!isLive) ...[
|
|
||||||
Builder(
|
|
||||||
builder: (context) {
|
|
||||||
void onChanged([_]) {
|
|
||||||
_waitUntilCompleted = !_waitUntilCompleted;
|
|
||||||
(context as Element).markNeedsBuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
return ListTile(
|
|
||||||
dense: true,
|
|
||||||
onTap: onChanged,
|
|
||||||
title: const Text('额外等待视频播放完毕', style: titleStyle),
|
|
||||||
trailing: Transform.scale(
|
|
||||||
alignment: Alignment.centerRight,
|
|
||||||
scale: 0.8,
|
|
||||||
child: Switch(
|
|
||||||
value: _waitUntilCompleted,
|
|
||||||
onChanged: onChanged,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
],
|
|
||||||
const SizedBox(height: 5),
|
|
||||||
Padding(
|
|
||||||
padding: const .only(left: 18),
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) {
|
|
||||||
return Row(
|
|
||||||
spacing: 12,
|
|
||||||
children: [
|
|
||||||
const Text('倒计时结束:', style: titleStyle),
|
|
||||||
..._ShutdownType.values.map(
|
|
||||||
(e) => ActionRowLineItem(
|
|
||||||
onTap: () {
|
|
||||||
_shutdownType = e;
|
|
||||||
(context as Element).markNeedsBuild();
|
|
||||||
},
|
|
||||||
text: ' ${e.label} ',
|
|
||||||
selectStatus: _shutdownType == e,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user