opt: btn, stack

Closes #775

Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
bggRGjQaUbCoE
2025-04-29 21:53:20 +08:00
parent 4abffeed32
commit b4ca42e0c0
55 changed files with 243 additions and 158 deletions

View File

@@ -232,6 +232,7 @@ class _ArticlePageState extends State<ArticlePage>
resizeToAvoidBottomInset: false,
appBar: _buildAppBar,
body: Stack(
clipBehavior: Clip.none,
children: [
SafeArea(
top: false,

View File

@@ -198,6 +198,7 @@ class _BangumiInfoState extends State<BangumiInfo> {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
clipBehavior: Clip.none,
children: [
GestureDetector(
onTap: () {

View File

@@ -41,6 +41,7 @@ class BangumiCardV extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: heroTag,

View File

@@ -46,6 +46,7 @@ class BangumiCardVMemberHome extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: heroTag,

View File

@@ -38,6 +38,7 @@ class BangumiCardVPgcIndex extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: bangumiItem['cover'],

View File

@@ -39,6 +39,7 @@ class BangumiCardVSearch extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item.cover,

View File

@@ -39,6 +39,7 @@ class BangumiCardVTimeline extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item.cover,

View File

@@ -286,6 +286,7 @@ abstract class CommonPublishPageState<T extends CommonPublishPage>
}
return Stack(
clipBehavior: Clip.none,
children: [
GestureDetector(
onTap: () {

View File

@@ -135,6 +135,7 @@ class _CreateDynPanelState extends CommonPublishPageState<CreateDynPanel> {
child: Padding(
padding: const EdgeInsets.all(16),
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Align(

View File

@@ -362,6 +362,7 @@ class _DynamicDetailPageState extends State<DynamicDetailPage>
}
Widget _buildBody(Orientation orientation, ThemeData theme) => Stack(
clipBehavior: Clip.none,
children: [
Builder(
builder: (context) {

View File

@@ -246,6 +246,7 @@ class _RepostPanelState extends CommonPublishPageState<RepostPanel> {
height: 34,
padding: const EdgeInsets.symmetric(horizontal: 16),
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Align(

View File

@@ -65,6 +65,7 @@ class AuthorPanel extends StatelessWidget {
: Utils.dateFormat(item.modules.moduleAuthor!.pubTs)
: item.modules.moduleAuthor?.pubTime;
return Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Align(
@@ -382,6 +383,7 @@ class AuthorPanel extends StatelessWidget {
},
minLeadingWidth: 0,
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shield_outlined, size: 19),

View File

@@ -441,6 +441,7 @@ Widget forWard(
children: [
if (floor == 1) const SizedBox(width: 12),
Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: item.modules.moduleDynamic!.major!.medialist!['cover'],

View File

@@ -79,6 +79,7 @@ Widget liveRcmdPanel(
builder: (context, box) {
double width = box.maxWidth;
return Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: liveRcmd.roomId.toString(),

View File

@@ -64,6 +64,7 @@ Widget videoSeasonWidget(
builder: (context, box) {
double width = box.maxWidth;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
width: width,

View File

@@ -114,7 +114,7 @@ class FavArticleItem extends StatelessWidget {
),
Positioned(
right: 12,
bottom: 0,
bottom: -6,
child: iconButton(
iconSize: 18,
context: context,

View File

@@ -451,6 +451,7 @@ class _FavDetailPageState extends State<FavDetailPage> {
}
FavDetailItemData item = loadingState.response![index];
return Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(
child: FavVideoCardH(

View File

@@ -96,6 +96,7 @@ class FavVideoCardH extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: videoItem.pic,
@@ -132,6 +133,7 @@ class FavVideoCardH extends StatelessWidget {
final theme = Theme.of(context);
return Expanded(
child: Stack(
clipBehavior: Clip.none,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,
@@ -179,7 +181,7 @@ class FavVideoCardH extends StatelessWidget {
if (onDelFav != null)
Positioned(
right: 0,
bottom: 0,
bottom: -8,
child: iconButton(
context: context,
icon: Icons.clear,

View File

@@ -118,6 +118,7 @@ class HistoryItem extends StatelessWidget {
);
},
child: Stack(
clipBehavior: Clip.none,
children: [
Padding(
padding: const EdgeInsets.symmetric(
@@ -128,110 +129,105 @@ class HistoryItem extends StatelessWidget {
mainAxisAlignment: MainAxisAlignment.start,
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
clipBehavior: Clip.none,
children: [
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: (videoItem.cover.isNullOrEmpty
? videoItem.covers?.firstOrNull ?? ''
: videoItem.cover),
width: maxWidth,
height: maxHeight,
),
if (!BusinessType
.hiddenDurationType.hiddenDurationType
.contains(videoItem.history.business))
PBadge(
text: videoItem.progress == -1
? '已看完'
: '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}',
right: 6.0,
bottom: 8.0,
type: 'gray',
),
// 右上角
if (BusinessType.showBadge.showBadge
.contains(videoItem.history.business) ||
videoItem.history.business ==
BusinessType.live.type)
PBadge(
text: videoItem.badge,
top: 6.0,
right: 6.0,
bottom: null,
left: null,
),
],
);
},
),
),
Positioned.fill(
child: AnimatedOpacity(
opacity: videoItem.checked == true ? 1 : 0,
duration: const Duration(milliseconds: 200),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: StyleString.mdRadius,
color: Colors.black.withOpacity(0.6),
AspectRatio(
aspectRatio: StyleString.aspectRatio,
child: LayoutBuilder(
builder: (context, boxConstraints) {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: (videoItem.cover.isNullOrEmpty
? videoItem.covers?.firstOrNull ?? ''
: videoItem.cover),
width: maxWidth,
height: maxHeight,
),
child: SizedBox(
width: 34,
height: 34,
child: AnimatedScale(
scale: videoItem.checked == true ? 1 : 0,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: IconButton(
tooltip: '取消选择',
style: ButtonStyle(
padding:
WidgetStateProperty.all(EdgeInsets.zero),
backgroundColor:
WidgetStateProperty.resolveWith(
(states) {
return theme.colorScheme.surface
.withOpacity(0.8);
},
if (!BusinessType
.hiddenDurationType.hiddenDurationType
.contains(videoItem.history.business))
PBadge(
text: videoItem.progress == -1
? '已看完'
: '${Utils.timeFormat(videoItem.progress)}/${Utils.timeFormat(videoItem.duration!)}',
right: 6.0,
bottom: 8.0,
type: 'gray',
),
// 右上角
if (BusinessType.showBadge.showBadge
.contains(videoItem.history.business) ||
videoItem.history.business ==
BusinessType.live.type)
PBadge(
text: videoItem.badge,
top: 6.0,
right: 6.0,
bottom: null,
left: null,
),
if (videoItem.duration != null &&
videoItem.duration != 0 &&
videoItem.progress != null &&
videoItem.progress != 0)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: videoProgressIndicator(
videoItem.progress == -1
? 1
: videoItem.progress! / videoItem.duration!,
),
),
Positioned.fill(
child: AnimatedOpacity(
opacity: videoItem.checked == true ? 1 : 0,
duration: const Duration(milliseconds: 200),
child: Container(
alignment: Alignment.center,
decoration: BoxDecoration(
borderRadius: StyleString.mdRadius,
color: Colors.black.withOpacity(0.6),
),
child: SizedBox(
width: 34,
height: 34,
child: AnimatedScale(
scale: videoItem.checked == true ? 1 : 0,
duration: const Duration(milliseconds: 250),
curve: Curves.easeInOut,
child: IconButton(
tooltip: '取消选择',
style: ButtonStyle(
padding: WidgetStateProperty.all(
EdgeInsets.zero),
backgroundColor:
WidgetStateProperty.resolveWith(
(states) {
return theme.colorScheme.surface
.withOpacity(0.8);
},
),
),
onPressed: () {
feedBack();
onChoose?.call();
},
icon: Icon(Icons.done_all_outlined,
color: theme.colorScheme.primary),
),
),
),
onPressed: () {
feedBack();
onChoose?.call();
},
icon: Icon(Icons.done_all_outlined,
color: theme.colorScheme.primary),
),
),
),
),
),
),
if (videoItem.duration != null &&
videoItem.duration != 0 &&
videoItem.progress != null &&
videoItem.progress != 0)
Positioned(
left: 0,
right: 0,
bottom: 0,
child: videoProgressIndicator(
videoItem.progress == -1
? 1
: videoItem.progress! / videoItem.duration!,
),
),
],
],
);
},
),
),
const SizedBox(width: 10),
videoContent(theme),
@@ -240,7 +236,7 @@ class HistoryItem extends StatelessWidget {
),
Positioned(
right: 12,
bottom: 12,
bottom: 0,
child: SizedBox(
width: 29,
height: 29,
@@ -339,6 +335,8 @@ class HistoryItem extends StatelessWidget {
if (videoItem.authorName != '')
Text(
videoItem.authorName!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: theme.textTheme.labelMedium!.fontSize,
color: theme.colorScheme.outline,

View File

@@ -82,6 +82,7 @@ class _LaterViewChildPageState extends State<LaterViewChildPage>
}
var videoItem = loadingState.response![index];
return Stack(
clipBehavior: Clip.none,
children: [
VideoCardH(
videoItem: videoItem,

View File

@@ -41,6 +41,7 @@ class _LaterSearchPageState
}
final item = list[index];
return Stack(
clipBehavior: Clip.none,
children: [
VideoCardH(
videoItem: item,

View File

@@ -39,6 +39,7 @@ class LiveCardV extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: heroTag,

View File

@@ -39,6 +39,7 @@ class LiveCardVFollow extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
Hero(
tag: heroTag,

View File

@@ -214,6 +214,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
return ColoredBox(
color: Colors.black,
child: Stack(
clipBehavior: Clip.none,
children: [
Obx(
() => isFullScreen
@@ -281,6 +282,7 @@ class _LiveRoomPageState extends State<LiveRoomPage>
resizeToAvoidBottomInset: false,
backgroundColor: Colors.transparent,
body: Stack(
clipBehavior: Clip.none,
children: [
_buildAppBar,
Column(

View File

@@ -22,6 +22,7 @@ class LiveRoomChat extends StatelessWidget {
@override
Widget build(BuildContext context) {
return Stack(
clipBehavior: Clip.none,
children: [
Obx(
() => ListView.separated(

View File

@@ -40,6 +40,7 @@ class SeasonSeriesCard extends StatelessWidget {
final double maxWidth = boxConstraints.maxWidth;
final double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item['meta']['cover'],

View File

@@ -441,6 +441,7 @@ class UserInfoCard extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
clipBehavior: Clip.none,
children: [
Column(
mainAxisSize: MainAxisSize.min,

View File

@@ -47,6 +47,7 @@ class MemberCoinsItem extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: coinItem.pic,

View File

@@ -171,6 +171,7 @@ class _LikeMePageState extends State<LikeMePage> {
width: 50,
height: 50,
child: Stack(
clipBehavior: Clip.none,
children: [
for (var j = 0;
j < item.users!.length && j < 4;

View File

@@ -35,6 +35,7 @@ class LiveItem extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: liveItem.cover,

View File

@@ -36,6 +36,7 @@ class SearchPgcItem extends StatelessWidget {
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
width: 111,

View File

@@ -1509,6 +1509,7 @@ List<SettingsModel> get extraSettings => [
defaultVal: false,
onTap: () => Get.toNamed('/sponsorBlock'),
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shield_outlined),
@@ -2063,6 +2064,7 @@ List<SettingsModel> get extraSettings => [
title: '发评反诈',
subtitle: '发送评论后检查评论是否可见',
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shield_outlined),
@@ -2088,6 +2090,7 @@ List<SettingsModel> get extraSettings => [
title: '发布/转发动态反诈',
subtitle: '发布/转发动态后检查动态是否可见',
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shield_outlined),
@@ -2101,6 +2104,7 @@ List<SettingsModel> get extraSettings => [
settingsType: SettingsType.sw1tch,
title: '屏蔽带货动态',
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shopping_bag_outlined, size: 14),
@@ -2117,6 +2121,7 @@ List<SettingsModel> get extraSettings => [
settingsType: SettingsType.sw1tch,
title: '屏蔽带货评论',
leading: const Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(Icons.shopping_bag_outlined, size: 14),

View File

@@ -75,6 +75,7 @@ class SubItem extends StatelessWidget {
: '其它:${subFolderItem.type}';
return Expanded(
child: Stack(
clipBehavior: Clip.none,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -57,6 +57,7 @@ class SubVideoCardH extends StatelessWidget {
double maxWidth = boxConstraints.maxWidth;
double maxHeight = boxConstraints.maxHeight;
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: videoItem.cover,
@@ -85,6 +86,7 @@ class SubVideoCardH extends StatelessWidget {
Widget videoContent(context) {
return Expanded(
child: Stack(
clipBehavior: Clip.none,
children: [
Column(
crossAxisAlignment: CrossAxisAlignment.start,

View File

@@ -193,6 +193,7 @@ class _PayCoinsPageState extends State<PayCoinsPage>
Widget _buildBody(isV) => Stack(
key: _key,
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Visibility(
@@ -268,6 +269,7 @@ class _PayCoinsPageState extends State<PayCoinsPage>
BlendMode.srcATop,
),
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
SlideTransition(
@@ -389,6 +391,7 @@ class _PayCoinsPageState extends State<PayCoinsPage>
],
const SizedBox(height: 10),
Stack(
clipBehavior: Clip.none,
alignment: Alignment.centerLeft,
children: [
GestureDetector(

View File

@@ -150,6 +150,7 @@ class _VideoInfoState extends State<VideoInfo> {
mainAxisSize: MainAxisSize.min,
children: [
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(
@@ -548,6 +549,7 @@ class _VideoInfoState extends State<VideoInfo> {
),
const SizedBox(height: 8),
Stack(
clipBehavior: Clip.none,
children: [
Row(
children: [

View File

@@ -157,6 +157,7 @@ class ActionItemState extends State<ActionItem>
mainAxisAlignment: MainAxisAlignment.center,
children: [
Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
if (widget.needAnim && !_hideCircle)

View File

@@ -96,6 +96,7 @@ class _PostPanelState extends CommonCollapseSlidePageState<PostPanel> {
Widget buildList(ThemeData theme) {
return list?.isNotEmpty == true
? Stack(
clipBehavior: Clip.none,
children: [
SingleChildScrollView(
controller: ScrollController(),

View File

@@ -104,6 +104,7 @@ class _VideoReplyPanelState extends State<VideoReplyPanel>
await _videoReplyController.onRefresh();
},
child: Stack(
clipBehavior: Clip.none,
children: [
CustomScrollView(
controller: widget.needController == false

View File

@@ -111,6 +111,7 @@ class ReplyItemGrpc extends StatelessWidget {
top: 8,
right: 12,
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.centerRight,
children: [
CachedNetworkImage(
@@ -1179,6 +1180,7 @@ class ReplyItemGrpc extends StatelessWidget {
onTap: () => menuActionHandler('checkReply'),
minLeadingWidth: 0,
leading: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
const Icon(Icons.shield_outlined, size: 19),

View File

@@ -165,6 +165,7 @@ class _VideoReplyReplyPanelState
},
child: Obx(
() => Stack(
clipBehavior: Clip.none,
children: [
ScrollablePositionedList.builder(
key: _listKey,

View File

@@ -552,6 +552,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
videoDetailController.scrollCtr.offset != 0 &&
context.orientation == Orientation.portrait;
return Stack(
clipBehavior: Clip.none,
children: [
AppBar(
backgroundColor: Colors.black,
@@ -639,6 +640,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
? animHeight
: videoDetailController.videoHeight,
flexibleSpace: Stack(
clipBehavior: Clip.none,
children: [
Builder(
builder: (context) {
@@ -702,6 +704,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
child: SizedBox(
height: kToolbarHeight,
child: Stack(
clipBehavior: Clip.none,
children: [
Align(
alignment: Alignment.centerLeft,
@@ -1182,6 +1185,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
);
Widget get childWhenDisabledLandscape => Stack(
clipBehavior: Clip.none,
children: [
Scaffold(
resizeToAvoidBottomInset: false,
@@ -1261,6 +1265,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
() => Visibility(
visible: videoDetailController.isShowCover.value,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned(
top: 0,
@@ -1634,6 +1639,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
MediaQuery.of(context).orientation == Orientation.portrait),
onPopInvokedWithResult: _onPopInvokedWithResult,
child: Stack(
clipBehavior: Clip.none,
children: [
Positioned.fill(child: ColoredBox(color: Colors.black)),
@@ -1860,6 +1866,7 @@ class _VideoDetailPageVState extends State<VideoDetailPageV>
);
if (videoDetailController.isPlayAll) {
return Stack(
clipBehavior: Clip.none,
children: [
introPanel(),
Positioned(

View File

@@ -2032,6 +2032,7 @@ class HeaderControlState extends State<HeaderControl> {
),
onPressed: () => videoDetailCtr.onBlock(context),
icon: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
Icon(

View File

@@ -179,6 +179,7 @@ class _MediaListPanelState
);
},
child: Stack(
clipBehavior: Clip.none,
children: [
Padding(
padding: const EdgeInsets.symmetric(
@@ -194,6 +195,7 @@ class _MediaListPanelState
child: LayoutBuilder(
builder: (context, boxConstraints) {
return Stack(
clipBehavior: Clip.none,
children: [
NetworkImgLayer(
src: item.cover,
@@ -233,6 +235,8 @@ class _MediaListPanelState
const Spacer(),
Text(
item.upper!.name!,
maxLines: 1,
overflow: TextOverflow.ellipsis,
style: TextStyle(
fontSize: 12,
color: theme.colorScheme.outline,
@@ -265,7 +269,7 @@ class _MediaListPanelState
if (showDelBtn && item.bvid != widget.getBvId())
Positioned(
right: 12,
bottom: 0,
bottom: -6,
child: InkWell(
customBorder: const CircleBorder(),
onTap: () {
@@ -281,7 +285,7 @@ class _MediaListPanelState
child: Icon(
Icons.clear,
size: 18,
color: theme.colorScheme.onSurfaceVariant,
color: theme.colorScheme.outline,
),
),
),