opt scrollPhysics

Signed-off-by: dom <githubaccount56556@proton.me>
This commit is contained in:
dom
2026-02-23 11:59:06 +08:00
parent d15ad4911d
commit ee04978e0c
2 changed files with 184 additions and 202 deletions

View File

@@ -200,6 +200,186 @@ class _AudioPageState extends State<AudioPage> {
builder: (context) {
final theme = Theme.of(context);
final colorScheme = theme.colorScheme;
Widget child = CustomScrollView(
controller: scrollController,
physics: _controller.reachStart
? null
: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverPadding(
padding: EdgeInsets.only(
bottom: MediaQuery.paddingOf(context).bottom + 100,
),
sliver: SliverList.builder(
itemCount: playlist.length,
itemBuilder: (_, index) {
if (index == playlist.length - 1) {
_controller.loadNext(context);
}
final isCurr = index == _controller.index;
final item = playlist[index];
if (item.parts.length > 1) {
final subId = _controller.subId.firstOrNull;
return ExpansionTile(
dense: true,
minTileHeight: 45,
initiallyExpanded: isCurr,
collapsedIconColor: isCurr ? colorScheme.primary : null,
iconColor: isCurr ? null : colorScheme.onSurfaceVariant,
controlAffinity: ListTileControlAffinity.leading,
title: Text(
item.arc.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: const TextStyle(fontSize: 14),
),
trailing: isCurr
? null
: iconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (index < _controller.index!) {
_controller.index -= 1;
}
playlist.removeAt(index);
(context as Element).markNeedsBuild();
},
iconColor: colorScheme.outline,
size: 28,
iconSize: 18,
),
children: item.parts.map((e) {
final isCurr = e.subId == subId;
return ListTile(
dense: true,
minTileHeight: 45,
contentPadding: const EdgeInsetsDirectional.only(
start: 56.0,
end: 24.0,
),
onTap: () {
Get.back();
if (!isCurr) {
_controller.playIndex(
index,
subId: [e.subId],
);
}
},
title: Text.rich(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: TextStyle(
fontSize: 14,
color: colorScheme.onSurfaceVariant,
),
TextSpan(
children: [
if (isCurr) ...[
WidgetSpan(
alignment: .bottom,
child: Image.asset(
'assets/images/live.gif',
width: 16,
height: 16,
cacheWidth: 16.cacheSize(
context,
),
color: colorScheme.primary,
),
),
const TextSpan(text: ' '),
],
TextSpan(text: e.title),
],
),
),
);
}).toList(),
);
}
return ListTile(
dense: true,
minTileHeight: 45,
onTap: () {
Get.back();
if (!isCurr) {
_controller.playIndex(index);
}
},
title: Text.rich(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: const TextStyle(fontSize: 14),
TextSpan(
children: [
if (isCurr) ...[
WidgetSpan(
alignment: .bottom,
child: Image.asset(
'assets/images/live.gif',
width: 16,
height: 16,
cacheWidth: 16.cacheSize(
context,
),
color: colorScheme.primary,
),
),
const TextSpan(text: ' '),
],
TextSpan(
text: item.arc.title,
),
],
),
),
trailing: isCurr
? null
: iconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (index < _controller.index!) {
_controller.index -= 1;
}
playlist.removeAt(index);
(context as Element).markNeedsBuild();
},
iconColor: colorScheme.outline,
size: 28,
iconSize: 18,
),
);
},
),
),
],
);
if (!_controller.reachStart) {
child = refreshIndicator(
onRefresh: () => _controller.loadPrev(context),
isClampingScrollPhysics: true,
child: child,
);
}
return FractionallySizedBox(
heightFactor:
PlatformUtils.isMobile && !context.mediaQuerySize.isPortrait
@@ -219,9 +399,7 @@ class _AudioPageState extends State<AudioPage> {
height: 3,
decoration: BoxDecoration(
color: colorScheme.outline,
borderRadius: const BorderRadius.all(
Radius.circular(3),
),
borderRadius: const .all(.circular(3)),
),
),
),
@@ -231,200 +409,8 @@ class _AudioPageState extends State<AudioPage> {
child: Material(
type: MaterialType.transparency,
child: Theme(
data: theme.copyWith(
dividerColor: Colors.transparent,
),
child: refreshIndicator(
onRefresh: () => _controller.loadPrev(context),
isClampingScrollPhysics: true,
child: CustomScrollView(
controller: scrollController,
physics: _controller.reachStart
? const ClampingScrollPhysics()
: const AlwaysScrollableScrollPhysics(
parent: ClampingScrollPhysics(),
),
slivers: [
SliverPadding(
padding: EdgeInsets.only(
bottom:
MediaQuery.paddingOf(context).bottom + 100,
),
sliver: SliverList.builder(
itemCount: playlist.length,
itemBuilder: (_, index) {
if (index == playlist.length - 1) {
_controller.loadNext(context);
}
final isCurr = index == _controller.index;
final item = playlist[index];
if (item.parts.length > 1) {
final subId = _controller.subId.firstOrNull;
return ExpansionTile(
dense: true,
minTileHeight: 45,
initiallyExpanded: isCurr,
collapsedIconColor: isCurr
? colorScheme.primary
: null,
iconColor: isCurr
? null
: colorScheme.onSurfaceVariant,
controlAffinity:
ListTileControlAffinity.leading,
title: Text(
item.arc.title,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: const TextStyle(fontSize: 14),
),
trailing: isCurr
? null
: iconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (index <
_controller.index!) {
_controller.index -= 1;
}
playlist.removeAt(index);
(context as Element)
.markNeedsBuild();
},
iconColor: colorScheme.outline,
size: 28,
iconSize: 18,
),
children: item.parts.map((e) {
final isCurr = e.subId == subId;
return ListTile(
dense: true,
minTileHeight: 45,
contentPadding:
const EdgeInsetsDirectional.only(
start: 56.0,
end: 24.0,
),
onTap: () {
Get.back();
if (!isCurr) {
_controller.playIndex(
index,
subId: [e.subId],
);
}
},
title: Text.rich(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: TextStyle(
fontSize: 14,
color: colorScheme
.onSurfaceVariant,
),
TextSpan(
children: [
if (isCurr) ...[
WidgetSpan(
alignment: .bottom,
child: Image.asset(
'assets/images/live.gif',
width: 16,
height: 16,
cacheWidth: 16.cacheSize(
context,
),
color:
colorScheme.primary,
),
),
const TextSpan(text: ' '),
],
TextSpan(text: e.title),
],
),
),
);
}).toList(),
);
}
return ListTile(
dense: true,
minTileHeight: 45,
onTap: () {
Get.back();
if (!isCurr) {
_controller.playIndex(index);
}
},
title: Text.rich(
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: isCurr
? TextStyle(
fontSize: 14,
color: colorScheme.primary,
fontWeight: FontWeight.bold,
)
: const TextStyle(fontSize: 14),
TextSpan(
children: [
if (isCurr) ...[
WidgetSpan(
alignment: .bottom,
child: Image.asset(
'assets/images/live.gif',
width: 16,
height: 16,
cacheWidth: 16.cacheSize(
context,
),
color: colorScheme.primary,
),
),
const TextSpan(text: ' '),
],
TextSpan(
text: item.arc.title,
),
],
),
),
trailing: isCurr
? null
: iconButton(
icon: const Icon(Icons.clear),
onPressed: () {
if (index < _controller.index!) {
_controller.index -= 1;
}
playlist.removeAt(index);
(context as Element)
.markNeedsBuild();
},
iconColor: colorScheme.outline,
size: 28,
iconSize: 18,
),
);
},
),
),
],
),
),
data: theme.copyWith(dividerColor: Colors.transparent),
child: child,
),
),
),