mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-08-05 18:20:10 +08:00
@@ -20,7 +20,6 @@ import 'package:PiliPlus/pages/article/widgets/opus_content.dart';
|
|||||||
import 'package:PiliPlus/pages/common/dyn/common_dyn_page.dart';
|
import 'package:PiliPlus/pages/common/dyn/common_dyn_page.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
||||||
import 'package:PiliPlus/pages/video/reply/widgets/reply_item_grpc.dart';
|
import 'package:PiliPlus/pages/video/reply/widgets/reply_item_grpc.dart';
|
||||||
import 'package:PiliPlus/utils/context_ext.dart';
|
|
||||||
import 'package:PiliPlus/utils/date_util.dart';
|
import 'package:PiliPlus/utils/date_util.dart';
|
||||||
import 'package:PiliPlus/utils/feed_back.dart';
|
import 'package:PiliPlus/utils/feed_back.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
@@ -70,19 +69,18 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final isPortrait = context.isPortrait;
|
final size = MediaQuery.sizeOf(context);
|
||||||
|
final maxWidth = size.width;
|
||||||
|
final isPortrait = size.height >= maxWidth;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: _buildAppBar(isPortrait),
|
appBar: _buildAppBar(isPortrait, maxWidth),
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(left: padding.left, right: padding.right),
|
||||||
left: padding.left,
|
|
||||||
right: padding.right,
|
|
||||||
),
|
|
||||||
child: Stack(
|
child: Stack(
|
||||||
clipBehavior: Clip.none,
|
clipBehavior: Clip.none,
|
||||||
children: [
|
children: [
|
||||||
_buildPage(theme, isPortrait),
|
_buildPage(theme, isPortrait, maxWidth),
|
||||||
_buildBottom(theme),
|
_buildBottom(theme),
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
@@ -90,101 +88,89 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildPage(ThemeData theme, bool isPortrait) {
|
Widget _buildPage(ThemeData theme, bool isPortrait, double maxWidth) {
|
||||||
return LayoutBuilder(
|
double padding = max(maxWidth / 2 - Grid.smallCardWidth, 0);
|
||||||
builder: (context, constraints) {
|
if (isPortrait) {
|
||||||
double padding = max(
|
return Padding(
|
||||||
context.width / 2 - Grid.smallCardWidth,
|
padding: EdgeInsets.symmetric(horizontal: padding),
|
||||||
0,
|
child: CustomScrollView(
|
||||||
);
|
controller: controller.scrollController,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
if (isPortrait) {
|
slivers: [
|
||||||
final maxWidth = constraints.maxWidth - 2 * padding - 24;
|
_buildContent(
|
||||||
return Padding(
|
theme,
|
||||||
padding: EdgeInsets.symmetric(horizontal: padding),
|
maxWidth - this.padding.horizontal - 2 * padding - 24,
|
||||||
child: CustomScrollView(
|
|
||||||
controller: controller.scrollController,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
slivers: [
|
|
||||||
_buildContent(theme, maxWidth),
|
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: Divider(
|
|
||||||
thickness: 8,
|
|
||||||
color: theme.dividerColor.withValues(
|
|
||||||
alpha: 0.05,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
buildReplyHeader(theme),
|
|
||||||
Obx(
|
|
||||||
() => _buildReplyList(
|
|
||||||
theme,
|
|
||||||
controller.loadingState.value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
),
|
||||||
);
|
SliverToBoxAdapter(
|
||||||
}
|
child: Divider(
|
||||||
|
thickness: 8,
|
||||||
padding = padding / 4;
|
color: theme.dividerColor.withValues(alpha: 0.05),
|
||||||
final flex = controller.ratio[0].toInt();
|
|
||||||
return Row(
|
|
||||||
crossAxisAlignment: CrossAxisAlignment.start,
|
|
||||||
children: [
|
|
||||||
Expanded(
|
|
||||||
flex: flex,
|
|
||||||
child: CustomScrollView(
|
|
||||||
controller: controller.scrollController,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
slivers: [
|
|
||||||
SliverPadding(
|
|
||||||
padding: EdgeInsets.only(
|
|
||||||
left: padding,
|
|
||||||
bottom: this.padding.bottom + 100,
|
|
||||||
),
|
|
||||||
sliver: _buildContent(
|
|
||||||
theme,
|
|
||||||
constraints.maxWidth * flex - padding - 24,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
VerticalDivider(
|
|
||||||
thickness: 8,
|
|
||||||
color: theme.dividerColor.withValues(alpha: 0.05),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: controller.ratio[1].toInt(),
|
|
||||||
child: Scaffold(
|
|
||||||
key: scaffoldKey,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
resizeToAvoidBottomInset: false,
|
|
||||||
body: refreshIndicator(
|
|
||||||
onRefresh: controller.onRefresh,
|
|
||||||
child: Padding(
|
|
||||||
padding: EdgeInsets.only(right: padding),
|
|
||||||
child: CustomScrollView(
|
|
||||||
controller: controller.scrollController,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
slivers: [
|
|
||||||
buildReplyHeader(theme),
|
|
||||||
Obx(
|
|
||||||
() => _buildReplyList(
|
|
||||||
theme,
|
|
||||||
controller.loadingState.value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
|
buildReplyHeader(theme),
|
||||||
|
Obx(() => _buildReplyList(theme, controller.loadingState.value)),
|
||||||
],
|
],
|
||||||
);
|
),
|
||||||
},
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
padding = padding / 4;
|
||||||
|
final flex = controller.ratio[0].toInt();
|
||||||
|
final flex1 = controller.ratio[1].toInt();
|
||||||
|
return Row(
|
||||||
|
crossAxisAlignment: CrossAxisAlignment.start,
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: flex,
|
||||||
|
child: CustomScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
slivers: [
|
||||||
|
SliverPadding(
|
||||||
|
padding: EdgeInsets.only(
|
||||||
|
left: padding,
|
||||||
|
bottom: this.padding.bottom + 100,
|
||||||
|
),
|
||||||
|
sliver: _buildContent(
|
||||||
|
theme,
|
||||||
|
(maxWidth - this.padding.horizontal) * flex / (flex + flex1) -
|
||||||
|
padding -
|
||||||
|
32,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
VerticalDivider(
|
||||||
|
thickness: 8,
|
||||||
|
color: theme.dividerColor.withValues(alpha: 0.05),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: flex1,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(right: padding),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
body: refreshIndicator(
|
||||||
|
onRefresh: controller.onRefresh,
|
||||||
|
child: CustomScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
slivers: [
|
||||||
|
buildReplyHeader(theme),
|
||||||
|
Obx(
|
||||||
|
() =>
|
||||||
|
_buildReplyList(theme, controller.loadingState.value),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -484,7 +470,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
PreferredSizeWidget _buildAppBar(bool isPortrait) => AppBar(
|
PreferredSizeWidget _buildAppBar(bool isPortrait, double maxWidth) => AppBar(
|
||||||
title: Obx(() {
|
title: Obx(() {
|
||||||
if (controller.isLoaded.value && controller.showTitle.value) {
|
if (controller.isLoaded.value && controller.showTitle.value) {
|
||||||
return Text(controller.summary.title ?? '');
|
return Text(controller.summary.title ?? '');
|
||||||
@@ -505,7 +491,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
|
|||||||
top: 56,
|
top: 56,
|
||||||
right: 16,
|
right: 16,
|
||||||
),
|
),
|
||||||
width: context.width / 4,
|
width: maxWidth / 4,
|
||||||
height: 32,
|
height: 32,
|
||||||
child: Builder(
|
child: Builder(
|
||||||
builder: (context) => Slider(
|
builder: (context) => Slider(
|
||||||
|
|||||||
@@ -163,42 +163,39 @@ abstract class CommonDynPageState<T extends CommonDynPage> extends State<T>
|
|||||||
EasyThrottle.throttle('replyReply', const Duration(milliseconds: 500), () {
|
EasyThrottle.throttle('replyReply', const Duration(milliseconds: 500), () {
|
||||||
int oid = replyItem.oid.toInt();
|
int oid = replyItem.oid.toInt();
|
||||||
int rpid = replyItem.id.toInt();
|
int rpid = replyItem.id.toInt();
|
||||||
Widget replyReplyPage({bool showBackBtn = true}) => Padding(
|
Widget replyReplyPage({bool showBackBtn = true}) => Scaffold(
|
||||||
padding: EdgeInsets.only(right: padding.right),
|
resizeToAvoidBottomInset: false,
|
||||||
child: Scaffold(
|
appBar: AppBar(
|
||||||
resizeToAvoidBottomInset: false,
|
primary: showBackBtn,
|
||||||
appBar: AppBar(
|
toolbarHeight: showBackBtn ? null : 45,
|
||||||
primary: showBackBtn,
|
title: const Text('评论详情'),
|
||||||
toolbarHeight: showBackBtn ? null : 45,
|
titleSpacing: showBackBtn ? null : 12,
|
||||||
title: const Text('评论详情'),
|
automaticallyImplyLeading: showBackBtn,
|
||||||
titleSpacing: showBackBtn ? null : 12,
|
actions: showBackBtn
|
||||||
automaticallyImplyLeading: showBackBtn,
|
? null
|
||||||
actions: showBackBtn
|
: [
|
||||||
? null
|
IconButton(
|
||||||
: [
|
tooltip: '关闭',
|
||||||
IconButton(
|
icon: const Icon(Icons.close, size: 20),
|
||||||
tooltip: '关闭',
|
onPressed: Get.back,
|
||||||
icon: const Icon(Icons.close, size: 20),
|
),
|
||||||
onPressed: Get.back,
|
],
|
||||||
),
|
shape: Border(
|
||||||
],
|
bottom: BorderSide(
|
||||||
shape: Border(
|
color: Theme.of(
|
||||||
bottom: BorderSide(
|
context,
|
||||||
color: Theme.of(
|
).colorScheme.outline.withValues(alpha: 0.1),
|
||||||
context,
|
|
||||||
).colorScheme.outline.withValues(alpha: 0.1),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
body: VideoReplyReplyPanel(
|
),
|
||||||
enableSlide: false,
|
body: VideoReplyReplyPanel(
|
||||||
id: id,
|
enableSlide: false,
|
||||||
oid: oid,
|
id: id,
|
||||||
rpid: rpid,
|
oid: oid,
|
||||||
isVideoDetail: false,
|
rpid: rpid,
|
||||||
replyType: controller.replyType,
|
isVideoDetail: false,
|
||||||
firstFloor: replyItem,
|
replyType: controller.replyType,
|
||||||
),
|
firstFloor: replyItem,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (this.context.isPortrait) {
|
if (this.context.isPortrait) {
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart';
|
|||||||
import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart';
|
import 'package:PiliPlus/pages/dynamics/widgets/dynamic_panel.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics_detail/controller.dart';
|
import 'package:PiliPlus/pages/dynamics_detail/controller.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
import 'package:PiliPlus/pages/dynamics_repost/view.dart';
|
||||||
import 'package:PiliPlus/utils/context_ext.dart';
|
|
||||||
import 'package:PiliPlus/utils/feed_back.dart';
|
import 'package:PiliPlus/utils/feed_back.dart';
|
||||||
import 'package:PiliPlus/utils/grid.dart';
|
import 'package:PiliPlus/utils/grid.dart';
|
||||||
import 'package:PiliPlus/utils/num_util.dart';
|
import 'package:PiliPlus/utils/num_util.dart';
|
||||||
@@ -54,117 +53,159 @@ class _DynamicDetailPageState extends CommonDynPageState<DynamicDetailPage> {
|
|||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final isPortrait = context.isPortrait;
|
final size = MediaQuery.sizeOf(context);
|
||||||
|
final maxWidth = size.width;
|
||||||
|
final isPortrait = size.height >= maxWidth;
|
||||||
return Scaffold(
|
return Scaffold(
|
||||||
resizeToAvoidBottomInset: false,
|
resizeToAvoidBottomInset: false,
|
||||||
appBar: AppBar(
|
appBar: _buildAppBar(isPortrait, maxWidth),
|
||||||
title: Padding(
|
|
||||||
padding: const EdgeInsets.only(right: 12),
|
|
||||||
child: Obx(
|
|
||||||
() {
|
|
||||||
final showTitle = controller.showTitle.value;
|
|
||||||
return AnimatedOpacity(
|
|
||||||
opacity: showTitle ? 1 : 0,
|
|
||||||
duration: const Duration(milliseconds: 300),
|
|
||||||
child: IgnorePointer(
|
|
||||||
ignoring: !showTitle,
|
|
||||||
child: AuthorPanel(
|
|
||||||
item: controller.dynItem,
|
|
||||||
isDetail: true,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
actions: isPortrait
|
|
||||||
? null
|
|
||||||
: [
|
|
||||||
IconButton(
|
|
||||||
tooltip: '页面比例调节',
|
|
||||||
onPressed: () => showDialog(
|
|
||||||
context: context,
|
|
||||||
builder: (context) => Align(
|
|
||||||
alignment: Alignment.topRight,
|
|
||||||
child: Container(
|
|
||||||
margin: const EdgeInsets.only(
|
|
||||||
top: 56,
|
|
||||||
right: 16,
|
|
||||||
),
|
|
||||||
width: context.width / 4,
|
|
||||||
height: 32,
|
|
||||||
child: Builder(
|
|
||||||
builder: (context) => Slider(
|
|
||||||
min: 1,
|
|
||||||
max: 100,
|
|
||||||
value: controller.ratio.first,
|
|
||||||
onChanged: (value) {
|
|
||||||
if (value >= 10 && value <= 90) {
|
|
||||||
value = value.toPrecision(2);
|
|
||||||
controller.ratio
|
|
||||||
..[0] = value
|
|
||||||
..[1] = 100 - value;
|
|
||||||
GStorage.setting.put(
|
|
||||||
SettingBoxKey.dynamicDetailRatio,
|
|
||||||
controller.ratio,
|
|
||||||
);
|
|
||||||
(context as Element).markNeedsBuild();
|
|
||||||
setState(() {});
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
icon: Transform.rotate(
|
|
||||||
angle: pi / 2,
|
|
||||||
child: const Icon(Icons.splitscreen, size: 19),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
const SizedBox(width: 16),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
body: Padding(
|
body: Padding(
|
||||||
padding: EdgeInsets.only(
|
padding: EdgeInsets.only(left: padding.left, right: padding.right),
|
||||||
left: padding.left,
|
|
||||||
right: padding.right,
|
|
||||||
),
|
|
||||||
child: isPortrait
|
child: isPortrait
|
||||||
? refreshIndicator(
|
? refreshIndicator(
|
||||||
onRefresh: controller.onRefresh,
|
onRefresh: controller.onRefresh,
|
||||||
child: _buildBody(isPortrait, theme),
|
child: _buildBody(theme, isPortrait, maxWidth),
|
||||||
)
|
)
|
||||||
: _buildBody(isPortrait, theme),
|
: _buildBody(theme, isPortrait, maxWidth),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
Widget _buildBody(bool isPortrait, ThemeData theme) => Stack(
|
PreferredSizeWidget _buildAppBar(bool isPortrait, double maxWidth) => AppBar(
|
||||||
clipBehavior: Clip.none,
|
title: Padding(
|
||||||
children: [
|
padding: const EdgeInsets.only(right: 12),
|
||||||
Builder(
|
child: Obx(
|
||||||
builder: (context) {
|
() {
|
||||||
double padding = max(context.width / 2 - Grid.smallCardWidth, 0);
|
final showTitle = controller.showTitle.value;
|
||||||
if (isPortrait) {
|
return AnimatedOpacity(
|
||||||
return CustomScrollView(
|
opacity: showTitle ? 1 : 0,
|
||||||
|
duration: const Duration(milliseconds: 300),
|
||||||
|
child: IgnorePointer(
|
||||||
|
ignoring: !showTitle,
|
||||||
|
child: AuthorPanel(
|
||||||
|
item: controller.dynItem,
|
||||||
|
isDetail: true,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
actions: isPortrait
|
||||||
|
? null
|
||||||
|
: [
|
||||||
|
IconButton(
|
||||||
|
tooltip: '页面比例调节',
|
||||||
|
onPressed: () => showDialog(
|
||||||
|
context: context,
|
||||||
|
builder: (context) => Align(
|
||||||
|
alignment: Alignment.topRight,
|
||||||
|
child: Container(
|
||||||
|
margin: const EdgeInsets.only(top: 56, right: 16),
|
||||||
|
width: maxWidth / 4,
|
||||||
|
height: 32,
|
||||||
|
child: Builder(
|
||||||
|
builder: (context) => Slider(
|
||||||
|
min: 1,
|
||||||
|
max: 100,
|
||||||
|
value: controller.ratio.first,
|
||||||
|
onChanged: (value) {
|
||||||
|
if (value >= 10 && value <= 90) {
|
||||||
|
value = value.toPrecision(2);
|
||||||
|
controller.ratio
|
||||||
|
..[0] = value
|
||||||
|
..[1] = 100 - value;
|
||||||
|
GStorage.setting.put(
|
||||||
|
SettingBoxKey.dynamicDetailRatio,
|
||||||
|
controller.ratio,
|
||||||
|
);
|
||||||
|
(context as Element).markNeedsBuild();
|
||||||
|
setState(() {});
|
||||||
|
}
|
||||||
|
},
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
icon: Transform.rotate(
|
||||||
|
angle: pi / 2,
|
||||||
|
child: const Icon(Icons.splitscreen, size: 19),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
const SizedBox(width: 16),
|
||||||
|
],
|
||||||
|
);
|
||||||
|
|
||||||
|
Widget _buildBody(ThemeData theme, bool isPortrait, double maxWidth) {
|
||||||
|
double padding = max(maxWidth / 2 - Grid.smallCardWidth, 0);
|
||||||
|
Widget child;
|
||||||
|
if (isPortrait) {
|
||||||
|
child = Padding(
|
||||||
|
padding: EdgeInsets.symmetric(horizontal: padding),
|
||||||
|
child: CustomScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
|
slivers: [
|
||||||
|
SliverToBoxAdapter(
|
||||||
|
child: DynamicPanel(
|
||||||
|
item: controller.dynItem,
|
||||||
|
isDetail: true,
|
||||||
|
callback: imageCallback,
|
||||||
|
maxWidth: maxWidth - this.padding.horizontal - 2 * padding,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
buildReplyHeader(theme),
|
||||||
|
Obx(() => replyList(theme, controller.loadingState.value)),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
padding = padding / 4;
|
||||||
|
final flex = controller.ratio[0].toInt();
|
||||||
|
final flex1 = controller.ratio[1].toInt();
|
||||||
|
child = Row(
|
||||||
|
children: [
|
||||||
|
Expanded(
|
||||||
|
flex: flex,
|
||||||
|
child: CustomScrollView(
|
||||||
controller: controller.scrollController,
|
controller: controller.scrollController,
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverPadding(
|
SliverPadding(
|
||||||
padding: EdgeInsets.symmetric(horizontal: padding),
|
padding: EdgeInsets.only(
|
||||||
sliver: SliverMainAxisGroup(
|
left: padding,
|
||||||
|
bottom: this.padding.bottom + 100,
|
||||||
|
),
|
||||||
|
sliver: SliverToBoxAdapter(
|
||||||
|
child: DynamicPanel(
|
||||||
|
item: controller.dynItem,
|
||||||
|
isDetail: true,
|
||||||
|
callback: imageCallback,
|
||||||
|
maxWidth:
|
||||||
|
(maxWidth - this.padding.horizontal) *
|
||||||
|
(flex / (flex + flex1)) -
|
||||||
|
padding,
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
),
|
||||||
|
Expanded(
|
||||||
|
flex: flex1,
|
||||||
|
child: Padding(
|
||||||
|
padding: EdgeInsets.only(right: padding),
|
||||||
|
child: Scaffold(
|
||||||
|
key: scaffoldKey,
|
||||||
|
backgroundColor: Colors.transparent,
|
||||||
|
resizeToAvoidBottomInset: false,
|
||||||
|
body: refreshIndicator(
|
||||||
|
onRefresh: controller.onRefresh,
|
||||||
|
child: CustomScrollView(
|
||||||
|
controller: controller.scrollController,
|
||||||
|
physics: const AlwaysScrollableScrollPhysics(),
|
||||||
slivers: [
|
slivers: [
|
||||||
SliverToBoxAdapter(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (_, constrains) => DynamicPanel(
|
|
||||||
item: controller.dynItem,
|
|
||||||
isDetail: true,
|
|
||||||
callback: imageCallback,
|
|
||||||
maxWidth: constrains.maxWidth,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
buildReplyHeader(theme),
|
buildReplyHeader(theme),
|
||||||
Obx(
|
Obx(
|
||||||
() => replyList(theme, controller.loadingState.value),
|
() => replyList(theme, controller.loadingState.value),
|
||||||
@@ -172,74 +213,20 @@ class _DynamicDetailPageState extends CommonDynPageState<DynamicDetailPage> {
|
|||||||
],
|
],
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
],
|
),
|
||||||
);
|
),
|
||||||
} else {
|
),
|
||||||
return Row(
|
],
|
||||||
children: [
|
);
|
||||||
Expanded(
|
}
|
||||||
flex: controller.ratio[0].toInt(),
|
return Stack(
|
||||||
child: CustomScrollView(
|
clipBehavior: Clip.none,
|
||||||
controller: controller.scrollController,
|
children: [
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
child,
|
||||||
slivers: [
|
_buildBottom(theme),
|
||||||
SliverPadding(
|
],
|
||||||
padding: EdgeInsets.only(
|
);
|
||||||
left: padding / 4,
|
}
|
||||||
bottom: this.padding.bottom + 100,
|
|
||||||
),
|
|
||||||
sliver: SliverToBoxAdapter(
|
|
||||||
child: LayoutBuilder(
|
|
||||||
builder: (_, constraints) => DynamicPanel(
|
|
||||||
item: controller.dynItem,
|
|
||||||
isDetail: true,
|
|
||||||
callback: imageCallback,
|
|
||||||
maxWidth: constraints.maxWidth,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
Expanded(
|
|
||||||
flex: controller.ratio[1].toInt(),
|
|
||||||
child: Scaffold(
|
|
||||||
key: scaffoldKey,
|
|
||||||
backgroundColor: Colors.transparent,
|
|
||||||
resizeToAvoidBottomInset: false,
|
|
||||||
body: refreshIndicator(
|
|
||||||
onRefresh: controller.onRefresh,
|
|
||||||
child: CustomScrollView(
|
|
||||||
controller: controller.scrollController,
|
|
||||||
physics: const AlwaysScrollableScrollPhysics(),
|
|
||||||
slivers: [
|
|
||||||
SliverPadding(
|
|
||||||
padding: EdgeInsets.only(right: padding / 4),
|
|
||||||
sliver: buildReplyHeader(theme),
|
|
||||||
),
|
|
||||||
SliverPadding(
|
|
||||||
padding: EdgeInsets.only(right: padding / 4),
|
|
||||||
sliver: Obx(
|
|
||||||
() => replyList(
|
|
||||||
theme,
|
|
||||||
controller.loadingState.value,
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
),
|
|
||||||
_buildBottom(theme),
|
|
||||||
],
|
|
||||||
);
|
|
||||||
|
|
||||||
Widget _buildBottom(ThemeData theme) {
|
Widget _buildBottom(ThemeData theme) {
|
||||||
return Positioned(
|
return Positioned(
|
||||||
|
|||||||
@@ -297,6 +297,7 @@ class _SavePanelState extends State<SavePanel> {
|
|||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final theme = Theme.of(context);
|
final theme = Theme.of(context);
|
||||||
final padding = MediaQuery.viewPaddingOf(context);
|
final padding = MediaQuery.viewPaddingOf(context);
|
||||||
|
final maxWidth = context.mediaQueryShortestSide;
|
||||||
return GestureDetector(
|
return GestureDetector(
|
||||||
behavior: HitTestBehavior.opaque,
|
behavior: HitTestBehavior.opaque,
|
||||||
onTap: Get.back,
|
onTap: Get.back,
|
||||||
@@ -312,17 +313,15 @@ class _SavePanelState extends State<SavePanel> {
|
|||||||
child: GestureDetector(
|
child: GestureDetector(
|
||||||
onTap: () {},
|
onTap: () {},
|
||||||
child: Container(
|
child: Container(
|
||||||
width: context.mediaQueryShortestSide,
|
width: maxWidth,
|
||||||
margin: const EdgeInsets.symmetric(horizontal: 12),
|
padding: const EdgeInsets.symmetric(horizontal: 12),
|
||||||
child: RepaintBoundary(
|
child: RepaintBoundary(
|
||||||
key: boundaryKey,
|
key: boundaryKey,
|
||||||
child: Container(
|
child: Container(
|
||||||
clipBehavior: Clip.hardEdge,
|
clipBehavior: Clip.hardEdge,
|
||||||
decoration: BoxDecoration(
|
decoration: BoxDecoration(
|
||||||
color: theme.colorScheme.surface,
|
color: theme.colorScheme.surface,
|
||||||
borderRadius: const BorderRadius.all(
|
borderRadius: const BorderRadius.all(Radius.circular(12)),
|
||||||
Radius.circular(12),
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
child: AnimatedSize(
|
child: AnimatedSize(
|
||||||
curve: Curves.easeInOut,
|
curve: Curves.easeInOut,
|
||||||
@@ -343,13 +342,11 @@ class _SavePanelState extends State<SavePanel> {
|
|||||||
)
|
)
|
||||||
else if (_item is DynamicItemModel)
|
else if (_item is DynamicItemModel)
|
||||||
IgnorePointer(
|
IgnorePointer(
|
||||||
child: LayoutBuilder(
|
child: DynamicPanel(
|
||||||
builder: (_, constrains) => DynamicPanel(
|
item: _item,
|
||||||
item: _item,
|
isDetail: true,
|
||||||
isDetail: true,
|
isSave: true,
|
||||||
isSave: true,
|
maxWidth: maxWidth - 24,
|
||||||
maxWidth: constrains.maxWidth,
|
|
||||||
),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (cover?.isNotEmpty == true &&
|
if (cover?.isNotEmpty == true &&
|
||||||
|
|||||||
@@ -414,6 +414,7 @@ class VideoDetailController extends GetxController
|
|||||||
} else {
|
} else {
|
||||||
childKey.currentState?.showBottomSheet(
|
childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => panel(),
|
(context) => panel(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -1381,6 +1382,7 @@ class VideoDetailController extends GetxController
|
|||||||
} else {
|
} else {
|
||||||
childKey.currentState?.showBottomSheet(
|
childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => PostPanel(
|
(context) => PostPanel(
|
||||||
videoDetailController: this,
|
videoDetailController: this,
|
||||||
plPlayerController: plPlayerController,
|
plPlayerController: plPlayerController,
|
||||||
@@ -1689,6 +1691,7 @@ class VideoDetailController extends GetxController
|
|||||||
} else {
|
} else {
|
||||||
childKey.currentState?.showBottomSheet(
|
childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => NoteListPage(
|
(context) => NoteListPage(
|
||||||
oid: aid,
|
oid: aid,
|
||||||
heroTag: heroTag,
|
heroTag: heroTag,
|
||||||
|
|||||||
@@ -143,6 +143,7 @@ class _NoteListPageState extends CommonSlidePageState<NoteListPage> {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
_key.currentState?.showBottomSheet(
|
_key.currentState?.showBottomSheet(
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => WebviewPage(
|
(context) => WebviewPage(
|
||||||
oid: widget.oid,
|
oid: widget.oid,
|
||||||
title: widget.title,
|
title: widget.title,
|
||||||
|
|||||||
@@ -362,6 +362,7 @@ class _VideoReplyReplyPanelState
|
|||||||
upMid: _controller.upMid,
|
upMid: _controller.upMid,
|
||||||
showDialogue: () => _key.currentState?.showBottomSheet(
|
showDialogue: () => _key.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => VideoReplyReplyPanel(
|
(context) => VideoReplyReplyPanel(
|
||||||
oid: replyItem.oid.toInt(),
|
oid: replyItem.oid.toInt(),
|
||||||
rpid: replyItem.root.toInt(),
|
rpid: replyItem.root.toInt(),
|
||||||
|
|||||||
@@ -87,50 +87,48 @@ class _SendDanmakuPanelState extends CommonTextPubPageState<SendDanmakuPanel> {
|
|||||||
super.dispose();
|
super.dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
Expanded get _buildColorPanel => Expanded(
|
Widget get _buildColorPanel => Expanded(
|
||||||
child: Obx(
|
child: Obx(
|
||||||
() => LayoutBuilder(
|
() {
|
||||||
key: ValueKey(_color.value),
|
final bool isCustomColor = !_colorList.contains(_color.value);
|
||||||
builder: (context, constraints) {
|
final int length = _colorList.length + (isCustomColor ? 1 : 0) + 1;
|
||||||
final int crossAxisCount = (constraints.maxWidth / 40).toInt();
|
return GridView.builder(
|
||||||
final bool isCustomColor = !_colorList.contains(_color.value);
|
shrinkWrap: true,
|
||||||
final int length = _colorList.length + (isCustomColor ? 1 : 0) + 1;
|
physics: const NeverScrollableScrollPhysics(),
|
||||||
return GridView.builder(
|
padding: EdgeInsets.zero,
|
||||||
shrinkWrap: true,
|
gridDelegate: const SliverGridDelegateWithMaxCrossAxisExtent(
|
||||||
physics: const NeverScrollableScrollPhysics(),
|
maxCrossAxisExtent: 42,
|
||||||
padding: EdgeInsets.zero,
|
crossAxisSpacing: 4,
|
||||||
gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
|
mainAxisSpacing: 4,
|
||||||
crossAxisCount: crossAxisCount,
|
),
|
||||||
crossAxisSpacing: 4,
|
itemCount: length,
|
||||||
mainAxisSpacing: 4,
|
itemBuilder: (context, index) {
|
||||||
),
|
if (index == length - 1) {
|
||||||
itemCount: length,
|
return GestureDetector(
|
||||||
itemBuilder: (context, index) {
|
onTap: _showColorPicker,
|
||||||
if (index == length - 1) {
|
child: Container(
|
||||||
return GestureDetector(
|
decoration: BoxDecoration(
|
||||||
onTap: _showColorPicker,
|
color: themeData.colorScheme.secondaryContainer,
|
||||||
child: Container(
|
borderRadius: const BorderRadius.all(
|
||||||
decoration: BoxDecoration(
|
Radius.circular(8),
|
||||||
color: themeData.colorScheme.secondaryContainer,
|
|
||||||
borderRadius: const BorderRadius.all(Radius.circular(8)),
|
|
||||||
),
|
|
||||||
alignment: Alignment.center,
|
|
||||||
margin: const EdgeInsets.all(2),
|
|
||||||
child: Icon(
|
|
||||||
size: 22,
|
|
||||||
Icons.edit,
|
|
||||||
color: themeData.colorScheme.onSecondaryContainer,
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
alignment: Alignment.center,
|
||||||
} else if (index == length - 2 && isCustomColor) {
|
margin: const EdgeInsets.all(2),
|
||||||
return _buildColorItem(_color.value);
|
child: Icon(
|
||||||
}
|
size: 22,
|
||||||
return _buildColorItem(_colorList[index]);
|
Icons.edit,
|
||||||
},
|
color: themeData.colorScheme.onSecondaryContainer,
|
||||||
);
|
),
|
||||||
},
|
),
|
||||||
),
|
);
|
||||||
|
} else if (index == length - 2 && isCustomColor) {
|
||||||
|
return _buildColorItem(_color.value);
|
||||||
|
}
|
||||||
|
return _buildColorItem(_colorList[index]);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
},
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@@ -2028,6 +2028,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
int rpid = replyItem.id.toInt();
|
int rpid = replyItem.id.toInt();
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => VideoReplyReplyPanel(
|
(context) => VideoReplyReplyPanel(
|
||||||
id: id,
|
id: id,
|
||||||
oid: oid,
|
oid: oid,
|
||||||
@@ -2046,6 +2047,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
void showAiBottomSheet() {
|
void showAiBottomSheet() {
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) =>
|
(context) =>
|
||||||
AiConclusionPanel(item: ugcIntroController.aiConclusionResult!),
|
AiConclusionPanel(item: ugcIntroController.aiConclusionResult!),
|
||||||
);
|
);
|
||||||
@@ -2057,6 +2059,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
) {
|
) {
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => PgcIntroPanel(
|
(context) => PgcIntroPanel(
|
||||||
item: videoDetail,
|
item: videoDetail,
|
||||||
videoTags: videoTags,
|
videoTags: videoTags,
|
||||||
@@ -2126,6 +2129,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
} else {
|
} else {
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => listSheetContent(),
|
(context) => listSheetContent(),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -2217,6 +2221,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
} else {
|
} else {
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
backgroundColor: Colors.transparent,
|
backgroundColor: Colors.transparent,
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) => ViewPointsPage(
|
(context) => ViewPointsPage(
|
||||||
videoDetailController: videoDetailController,
|
videoDetailController: videoDetailController,
|
||||||
plPlayerController: plPlayerController,
|
plPlayerController: plPlayerController,
|
||||||
@@ -2241,6 +2246,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
|
|||||||
void onShowMemberPage(int? mid) {
|
void onShowMemberPage(int? mid) {
|
||||||
videoDetailController.childKey.currentState?.showBottomSheet(
|
videoDetailController.childKey.currentState?.showBottomSheet(
|
||||||
shape: const RoundedRectangleBorder(),
|
shape: const RoundedRectangleBorder(),
|
||||||
|
constraints: const BoxConstraints(),
|
||||||
(context) {
|
(context) {
|
||||||
return HorizontalMemberPage(
|
return HorizontalMemberPage(
|
||||||
mid: mid,
|
mid: mid,
|
||||||
|
|||||||
@@ -1378,6 +1378,8 @@ class _PLVideoPlayerState extends State<PLVideoPlayer>
|
|||||||
child:
|
child:
|
||||||
widget.bottomControl ??
|
widget.bottomControl ??
|
||||||
BottomControl(
|
BottomControl(
|
||||||
|
maxWidth: maxWidth,
|
||||||
|
isFullScreen: isFullScreen,
|
||||||
controller: plPlayerController,
|
controller: plPlayerController,
|
||||||
buildBottomControl: () =>
|
buildBottomControl: () =>
|
||||||
buildBottomControl(maxWidth > maxHeight),
|
buildBottomControl(maxWidth > maxHeight),
|
||||||
|
|||||||
@@ -11,11 +11,15 @@ import 'package:get/get.dart';
|
|||||||
|
|
||||||
class BottomControl extends StatelessWidget {
|
class BottomControl extends StatelessWidget {
|
||||||
const BottomControl({
|
const BottomControl({
|
||||||
|
super.key,
|
||||||
|
required this.maxWidth,
|
||||||
|
required this.isFullScreen,
|
||||||
required this.controller,
|
required this.controller,
|
||||||
required this.buildBottomControl,
|
required this.buildBottomControl,
|
||||||
super.key,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
final double maxWidth;
|
||||||
|
final bool isFullScreen;
|
||||||
final PlPlayerController controller;
|
final PlPlayerController controller;
|
||||||
final Widget Function() buildBottomControl;
|
final Widget Function() buildBottomControl;
|
||||||
|
|
||||||
@@ -33,130 +37,125 @@ class BottomControl extends StatelessWidget {
|
|||||||
children: [
|
children: [
|
||||||
Padding(
|
Padding(
|
||||||
padding: const EdgeInsets.fromLTRB(10, 0, 10, 7),
|
padding: const EdgeInsets.fromLTRB(10, 0, 10, 7),
|
||||||
child: LayoutBuilder(
|
child: Obx(
|
||||||
builder: (context, constraints) {
|
() => Stack(
|
||||||
final maxWidth = constraints.maxWidth;
|
clipBehavior: Clip.none,
|
||||||
return Obx(
|
alignment: Alignment.bottomCenter,
|
||||||
() => Stack(
|
children: [
|
||||||
clipBehavior: Clip.none,
|
Obx(() {
|
||||||
alignment: Alignment.bottomCenter,
|
final int value = controller.sliderPositionSeconds.value;
|
||||||
children: [
|
final int max = controller.durationSeconds.value.inSeconds;
|
||||||
Obx(() {
|
final int buffer = controller.bufferedSeconds.value;
|
||||||
final int value =
|
if (value > max || max <= 0) {
|
||||||
controller.sliderPositionSeconds.value;
|
return const SizedBox.shrink();
|
||||||
final int max =
|
}
|
||||||
controller.durationSeconds.value.inSeconds;
|
return ProgressBar(
|
||||||
final int buffer = controller.bufferedSeconds.value;
|
progress: Duration(seconds: value),
|
||||||
if (value > max || max <= 0) {
|
buffered: Duration(seconds: buffer),
|
||||||
return const SizedBox.shrink();
|
total: Duration(seconds: max),
|
||||||
|
progressBarColor: colorTheme,
|
||||||
|
baseBarColor: Colors.white.withValues(alpha: 0.2),
|
||||||
|
bufferedBarColor: colorTheme.withValues(alpha: 0.4),
|
||||||
|
timeLabelLocation: TimeLabelLocation.none,
|
||||||
|
thumbColor: colorTheme,
|
||||||
|
barHeight: 3.5,
|
||||||
|
thumbRadius: 7,
|
||||||
|
onDragStart: (duration) {
|
||||||
|
feedBack();
|
||||||
|
controller.onChangedSliderStart(duration.timeStamp);
|
||||||
|
},
|
||||||
|
onDragUpdate: (duration) {
|
||||||
|
if (controller.showSeekPreview) {
|
||||||
|
controller.updatePreviewIndex(
|
||||||
|
duration.timeStamp.inSeconds,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
return ProgressBar(
|
double newProgress = duration.timeStamp.inSeconds / max;
|
||||||
progress: Duration(seconds: value),
|
if ((newProgress - lastAnnouncedValue).abs() > 0.02) {
|
||||||
buffered: Duration(seconds: buffer),
|
accessibilityDebounce?.cancel();
|
||||||
total: Duration(seconds: max),
|
accessibilityDebounce = Timer(
|
||||||
progressBarColor: colorTheme,
|
const Duration(milliseconds: 200),
|
||||||
baseBarColor: Colors.white.withValues(alpha: 0.2),
|
() {
|
||||||
bufferedBarColor: colorTheme.withValues(alpha: 0.4),
|
SemanticsService.announce(
|
||||||
timeLabelLocation: TimeLabelLocation.none,
|
"${(newProgress * 100).round()}%",
|
||||||
thumbColor: colorTheme,
|
TextDirection.ltr,
|
||||||
barHeight: 3.5,
|
|
||||||
thumbRadius: 7,
|
|
||||||
onDragStart: (duration) {
|
|
||||||
feedBack();
|
|
||||||
controller.onChangedSliderStart(duration.timeStamp);
|
|
||||||
},
|
|
||||||
onDragUpdate: (duration) {
|
|
||||||
if (controller.showSeekPreview) {
|
|
||||||
controller.updatePreviewIndex(
|
|
||||||
duration.timeStamp.inSeconds,
|
|
||||||
);
|
);
|
||||||
}
|
lastAnnouncedValue = newProgress;
|
||||||
double newProgress =
|
},
|
||||||
duration.timeStamp.inSeconds / max;
|
);
|
||||||
if ((newProgress - lastAnnouncedValue).abs() >
|
}
|
||||||
0.02) {
|
controller.onUpdatedSliderProgress(
|
||||||
accessibilityDebounce?.cancel();
|
duration.timeStamp,
|
||||||
accessibilityDebounce = Timer(
|
|
||||||
const Duration(milliseconds: 200),
|
|
||||||
() {
|
|
||||||
SemanticsService.announce(
|
|
||||||
"${(newProgress * 100).round()}%",
|
|
||||||
TextDirection.ltr,
|
|
||||||
);
|
|
||||||
lastAnnouncedValue = newProgress;
|
|
||||||
},
|
|
||||||
);
|
|
||||||
}
|
|
||||||
controller.onUpdatedSliderProgress(
|
|
||||||
duration.timeStamp,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
onSeek: (duration) {
|
|
||||||
if (controller.showSeekPreview) {
|
|
||||||
controller.showPreview.value = false;
|
|
||||||
}
|
|
||||||
controller
|
|
||||||
..onChangedSliderEnd()
|
|
||||||
..onChangedSlider(duration.inSeconds.toDouble())
|
|
||||||
..seekTo(
|
|
||||||
Duration(seconds: duration.inSeconds),
|
|
||||||
isSeek: false,
|
|
||||||
);
|
|
||||||
SemanticsService.announce(
|
|
||||||
"${(duration.inSeconds / max * 100).round()}%",
|
|
||||||
TextDirection.ltr,
|
|
||||||
);
|
|
||||||
},
|
|
||||||
);
|
);
|
||||||
}),
|
},
|
||||||
if (controller.segmentList.isNotEmpty)
|
onSeek: (duration) {
|
||||||
Positioned(
|
if (controller.showSeekPreview) {
|
||||||
left: 0,
|
controller.showPreview.value = false;
|
||||||
right: 0,
|
}
|
||||||
bottom: 5.25,
|
controller
|
||||||
child: IgnorePointer(
|
..onChangedSliderEnd()
|
||||||
child: RepaintBoundary(
|
..onChangedSlider(duration.inSeconds.toDouble())
|
||||||
child: CustomPaint(
|
..seekTo(
|
||||||
key: const Key('segmentList'),
|
Duration(seconds: duration.inSeconds),
|
||||||
size: const Size(double.infinity, 3.5),
|
isSeek: false,
|
||||||
painter: SegmentProgressBar(
|
);
|
||||||
segmentColors: controller.segmentList,
|
SemanticsService.announce(
|
||||||
),
|
"${(duration.inSeconds / max * 100).round()}%",
|
||||||
),
|
TextDirection.ltr,
|
||||||
|
);
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}),
|
||||||
|
if (controller.segmentList.isNotEmpty)
|
||||||
|
Positioned(
|
||||||
|
left: 0,
|
||||||
|
right: 0,
|
||||||
|
bottom: 5.25,
|
||||||
|
child: IgnorePointer(
|
||||||
|
child: RepaintBoundary(
|
||||||
|
child: CustomPaint(
|
||||||
|
key: const Key('segmentList'),
|
||||||
|
size: const Size(double.infinity, 3.5),
|
||||||
|
painter: SegmentProgressBar(
|
||||||
|
segmentColors: controller.segmentList,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
if (controller.viewPointList.isNotEmpty &&
|
),
|
||||||
controller.showVP.value) ...[
|
),
|
||||||
Positioned(
|
if (controller.viewPointList.isNotEmpty &&
|
||||||
left: 0,
|
controller.showVP.value) ...[
|
||||||
right: 0,
|
Positioned(
|
||||||
bottom: 5.25,
|
left: 0,
|
||||||
child: IgnorePointer(
|
right: 0,
|
||||||
child: RepaintBoundary(
|
bottom: 5.25,
|
||||||
child: CustomPaint(
|
child: IgnorePointer(
|
||||||
key: const Key('viewPointList'),
|
child: RepaintBoundary(
|
||||||
size: const Size(double.infinity, 3.5),
|
child: CustomPaint(
|
||||||
painter: SegmentProgressBar(
|
key: const Key('viewPointList'),
|
||||||
segmentColors: controller.viewPointList,
|
size: const Size(double.infinity, 3.5),
|
||||||
),
|
painter: SegmentProgressBar(
|
||||||
),
|
segmentColors: controller.viewPointList,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
buildViewPointWidget(
|
),
|
||||||
controller,
|
),
|
||||||
8.75,
|
buildViewPointWidget(
|
||||||
maxWidth,
|
controller,
|
||||||
),
|
8.75,
|
||||||
],
|
maxWidth -
|
||||||
if (controller.dmTrend.isNotEmpty &&
|
40 -
|
||||||
controller.showDmTreandChart.value)
|
(isFullScreen
|
||||||
buildDmChart(theme, controller, 4.5),
|
? MediaQuery.viewPaddingOf(context).horizontal
|
||||||
],
|
: 0),
|
||||||
),
|
),
|
||||||
);
|
],
|
||||||
},
|
if (controller.dmTrend.isNotEmpty &&
|
||||||
|
controller.showDmTreandChart.value)
|
||||||
|
buildDmChart(theme, controller, 4.5),
|
||||||
|
],
|
||||||
|
),
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
buildBottomControl(),
|
buildBottomControl(),
|
||||||
|
|||||||
Reference in New Issue
Block a user