feat: cross row select (#2437)

* feat(wip): cross row select

* fix patch

Signed-off-by: dom <githubaccount56556@proton.me>

* update

Signed-off-by: dom <githubaccount56556@proton.me>

---------

Co-authored-by: dom <githubaccount56556@proton.me>
This commit is contained in:
My-Responsitories
2026-07-03 13:37:45 +00:00
committed by GitHub
parent 204715266f
commit b540647222
6 changed files with 472 additions and 226 deletions

View File

@@ -74,21 +74,27 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
if (isPortrait) {
return Padding(
padding: EdgeInsets.symmetric(horizontal: padding),
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
_buildContent(
maxWidth - this.padding.horizontal - 2 * padding - 24,
),
SliverToBoxAdapter(
child: Divider(
thickness: 8,
color: theme.dividerColor.withValues(alpha: 0.05),
child: SelectionArea(
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
_buildContent(
maxWidth - this.padding.horizontal - 2 * padding - 24,
),
),
buildReplyHeader(),
Obx(() => replyList(controller.loadingState.value)),
],
SelectionContainer.disabled(
child: SliverToBoxAdapter(
child: Divider(
thickness: 8,
color: theme.dividerColor.withValues(alpha: 0.05),
),
),
),
SelectionContainer.disabled(child: buildReplyHeader()),
SelectionContainer.disabled(
child: Obx(() => replyList(controller.loadingState.value)),
),
],
),
),
);
}
@@ -101,21 +107,25 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
children: [
Expanded(
flex: flex,
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverPadding(
padding: EdgeInsets.only(
left: padding,
bottom: this.padding.bottom + 100,
child: SelectionArea(
child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: [
SliverPadding(
padding: EdgeInsets.only(
left: padding,
bottom: this.padding.bottom + 100,
),
sliver: _buildContent(
(maxWidth - this.padding.horizontal) *
flex /
(flex + flex1) -
padding -
32,
),
),
sliver: _buildContent(
(maxWidth - this.padding.horizontal) * flex / (flex + flex1) -
padding -
32,
),
),
],
],
),
),
),
VerticalDivider(
@@ -151,7 +161,7 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
sliver: Obx(
() {
if (controller.isLoaded.value) {
late Widget content;
final Widget content;
if (controller.opus != null) {
// if (kDebugMode) debugPrint('json page');
content = OpusContent(
@@ -159,9 +169,9 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
images: controller.images,
maxWidth: maxWidth,
);
} else if (controller.opusData?.modules.moduleBlocked != null) {
} else if (controller.opusData?.modules.moduleBlocked
case final moduleBlocked?) {
// if (kDebugMode) debugPrint('moduleBlocked');
final moduleBlocked = controller.opusData!.modules.moduleBlocked!;
content = SliverToBoxAdapter(
child: moduleBlockedItem(context, theme, moduleBlocked),
);
@@ -201,128 +211,119 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
content = const SliverToBoxAdapter(child: Text('NULL'));
}
int? pubTime =
final pubTime =
controller.opusData?.modules.moduleAuthor?.pubTs ??
controller.articleData?.publishTime;
return SliverMainAxisGroup(
slivers: [
if (controller.type != 'read' &&
controller
.opusData
?.modules
.moduleTop
?.display
?.album
?.pics
?.isNotEmpty ==
true)
SliverToBoxAdapter(
child: Builder(
builder: (context) {
final pics = controller
.opusData!
.modules
.moduleTop!
.display!
.album!
.pics!;
final length = pics.length;
final first = pics.first;
double height;
if (first.height != null && first.width != null) {
final ratio = first.height! / first.width!;
height = min(maxWidth * ratio, maxHeight * 0.55);
} else {
height = maxHeight * 0.55;
}
return Stack(
clipBehavior: Clip.none,
children: [
Container(
height: height,
width: maxWidth,
margin: const EdgeInsets.only(bottom: 10),
child: PageView.builder(
physics: clampingScrollPhysics,
onPageChanged: (value) =>
controller.topIndex.value = value,
itemCount: length,
itemBuilder: (context, index) {
final pic = pics[index];
int? memCacheWidth, memCacheHeight;
if (pic.isLongPic ?? false) {
memCacheWidth = maxWidth.cacheSize(context);
} else if (pic.width != null &&
pic.height != null) {
if (pic.width! > pic.height!) {
if (controller.type != 'read')
if (controller.opusData?.modules.moduleTop?.display?.album?.pics
case final pics? when pics.isNotEmpty)
SliverToBoxAdapter(
child: Builder(
builder: (context) {
final length = pics.length;
final first = pics.first;
double height;
if (first.height != null && first.width != null) {
final ratio = first.height! / first.width!;
height = min(maxWidth * ratio, maxHeight * 0.55);
} else {
height = maxHeight * 0.55;
}
return Stack(
clipBehavior: Clip.none,
children: [
Container(
height: height,
width: maxWidth,
margin: const EdgeInsets.only(bottom: 10),
child: PageView.builder(
physics: clampingScrollPhysics,
onPageChanged: (value) =>
controller.topIndex.value = value,
itemCount: length,
itemBuilder: (context, index) {
final pic = pics[index];
int? memCacheWidth, memCacheHeight;
if (pic.isLongPic ?? false) {
memCacheWidth = maxWidth.cacheSize(context);
} else {
memCacheHeight = height.cacheSize(context);
} else if (pic.width != null &&
pic.height != null) {
if (pic.width! > pic.height!) {
memCacheWidth = maxWidth.cacheSize(
context,
);
} else {
memCacheHeight = height.cacheSize(
context,
);
}
}
}
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => PageUtils.imageView(
quality: 60,
imgList: pics
.map((e) => SourceModel(url: e.url!))
.toList(),
initialPage: index,
),
child: Hero(
tag: pic.url!,
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
CachedNetworkImage(
height: height,
width: maxWidth,
memCacheWidth: memCacheWidth,
memCacheHeight: memCacheHeight,
fit: pic.isLongPic == true
? BoxFit.cover
: null,
imageUrl: ImageUtils.thumbnailUrl(
pic.url,
60,
),
fadeInDuration: const Duration(
milliseconds: 120,
),
fadeOutDuration: const Duration(
milliseconds: 120,
),
placeholder: (_, _) =>
const SizedBox.shrink(),
),
if (pic.isLongPic == true)
const PBadge(
right: 12,
bottom: 12,
text: '长图',
type: .primary,
),
],
return GestureDetector(
behavior: HitTestBehavior.opaque,
onTap: () => PageUtils.imageView(
quality: 60,
imgList: pics
.map((e) => SourceModel(url: e.url!))
.toList(),
initialPage: index,
),
),
);
},
child: Hero(
tag: pic.url!,
child: Stack(
clipBehavior: Clip.none,
alignment: Alignment.center,
children: [
CachedNetworkImage(
height: height,
width: maxWidth,
memCacheWidth: memCacheWidth,
memCacheHeight: memCacheHeight,
fit: pic.isLongPic == true
? BoxFit.cover
: null,
imageUrl: ImageUtils.thumbnailUrl(
pic.url,
60,
),
fadeInDuration: const Duration(
milliseconds: 120,
),
fadeOutDuration: const Duration(
milliseconds: 120,
),
placeholder: (_, _) =>
const SizedBox.shrink(),
),
if (pic.isLongPic == true)
const PBadge(
right: 12,
bottom: 12,
text: '长图',
type: .primary,
),
],
),
),
);
},
),
),
),
Obx(
() => PBadge(
top: 12,
right: 12,
type: PBadgeType.gray,
text: '${controller.topIndex.value + 1}/$length',
Obx(
() => PBadge(
top: 12,
right: 12,
type: PBadgeType.gray,
text:
'${controller.topIndex.value + 1}/$length',
),
),
),
],
);
},
],
);
},
),
),
),
if (controller.summary.title != null)
SliverToBoxWithVisibilityAdapter(
onVisibilityChanged: (bool visible) =>
@@ -342,39 +343,41 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
onTap: () => Get.toNamed(
'/member?mid=${controller.summary.author?.mid}',
),
child: Row(
children: [
NetworkImgLayer(
width: 40,
height: 40,
type: ImageType.avatar,
src: controller.summary.author?.face,
),
const SizedBox(width: 10),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
controller.summary.author?.name ?? '',
style: TextStyle(
fontSize:
theme.textTheme.titleSmall!.fontSize,
),
),
if (pubTime != null)
child: SelectionContainer.disabled(
child: Row(
children: [
NetworkImgLayer(
width: 40,
height: 40,
type: ImageType.avatar,
src: controller.summary.author?.face,
),
const SizedBox(width: 10),
Flexible(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(
DateFormatUtils.format(pubTime),
controller.summary.author?.name ?? '',
style: TextStyle(
color: theme.colorScheme.outline,
fontSize:
theme.textTheme.labelSmall!.fontSize,
theme.textTheme.titleSmall!.fontSize,
),
),
],
if (pubTime != null)
Text(
DateFormatUtils.format(pubTime),
style: TextStyle(
color: theme.colorScheme.outline,
fontSize:
theme.textTheme.labelSmall!.fontSize,
),
),
],
),
),
),
],
],
),
),
),
),
@@ -382,9 +385,11 @@ class _ArticlePageState extends CommonDynPageState<ArticlePage> {
if (controller.type != 'read' &&
controller.opusData?.modules.moduleCollection != null)
SliverToBoxAdapter(
child: opusCollection(
theme,
controller.opusData!.modules.moduleCollection!,
child: SelectionContainer.disabled(
child: opusCollection(
theme,
controller.opusData!.modules.moduleCollection!,
),
),
),
content,