feat: cross row select (#867)

This commit is contained in:
My-Responsitories
2025-05-25 19:59:56 +08:00
committed by GitHub
parent 76a5b6221d
commit 89a077be5c
4 changed files with 249 additions and 250 deletions

View File

@@ -126,17 +126,15 @@ Widget htmlRender({
margin: Margins.zero,
),
};
return SelectionArea(
child: element != null
? Html.fromElement(
documentElement: element,
extensions: extensions,
style: style,
)
: Html(
data: html,
extensions: extensions,
style: style,
),
);
return element != null
? Html.fromElement(
documentElement: element,
extensions: extensions,
style: style,
)
: Html(
data: html,
extensions: extensions,
style: style,
);
}

View File

@@ -69,78 +69,76 @@ class OpusContent extends StatelessWidget {
switch (element.paraType) {
case 1 || 4:
final isQuote = element.paraType == 4;
Widget widget = SelectionArea(
child: Text.rich(
textAlign: element.align == 1 ? TextAlign.center : null,
TextSpan(
children: element.text?.nodes?.map((item) {
switch (item.type) {
case 'TEXT_NODE_TYPE_RICH' when (item.rich != null):
Rich rich = item.rich!;
switch (rich.type) {
case 'RICH_TEXT_NODE_TYPE_EMOJI':
Emoji emoji = rich.emoji!;
final size = 20.0 * emoji.size;
return WidgetSpan(
child: NetworkImgLayer(
width: size,
height: size,
src: emoji.url,
type: ImageType.emote,
),
);
default:
return TextSpan(
text:
'${rich.type == 'RICH_TEXT_NODE_TYPE_WEB' ? '\u{1F517}' : ''}${item.rich!.text}',
style: _getStyle(
rich.style,
rich.type == 'RICH_TEXT_NODE_TYPE_TEXT'
? null
: colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
switch (rich.type) {
case 'RICH_TEXT_NODE_TYPE_AT':
Get.toNamed('/member?mid=${rich.rid}');
// case 'RICH_TEXT_NODE_TYPE_TOPIC':
default:
if (rich.jumpUrl != null) {
PiliScheme.routePushFromUrl(
rich.jumpUrl!,
);
}
}
},
);
}
case 'TEXT_NODE_TYPE_FORMULA' when (item.formula != null):
return TextSpan(
children: [
WidgetSpan(
child: CachedNetworkSVGImage(
height: 65,
'https://api.bilibili.com/x/web-frontend/mathjax/tex?formula=${Uri.encodeComponent(item.formula!.latexContent!)}',
colorFilter: ColorFilter.mode(
colorScheme.onSurfaceVariant,
BlendMode.srcIn,
),
alignment: Alignment.centerLeft,
placeholderBuilder: (_) =>
const SizedBox.shrink(),
),
Widget widget = Text.rich(
textAlign: element.align == 1 ? TextAlign.center : null,
TextSpan(
children: element.text?.nodes?.map((item) {
switch (item.type) {
case 'TEXT_NODE_TYPE_RICH' when (item.rich != null):
Rich rich = item.rich!;
switch (rich.type) {
case 'RICH_TEXT_NODE_TYPE_EMOJI':
Emoji emoji = rich.emoji!;
final size = 20.0 * emoji.size;
return WidgetSpan(
child: NetworkImgLayer(
width: size,
height: size,
src: emoji.url,
type: ImageType.emote,
),
],
);
default:
return _getSpan(
item.word,
isQuote ? colorScheme.onSurfaceVariant : null,
);
}
}).toList()),
),
);
default:
return TextSpan(
text:
'${rich.type == 'RICH_TEXT_NODE_TYPE_WEB' ? '\u{1F517}' : ''}${item.rich!.text}',
style: _getStyle(
rich.style,
rich.type == 'RICH_TEXT_NODE_TYPE_TEXT'
? null
: colorScheme.primary,
),
recognizer: TapGestureRecognizer()
..onTap = () {
switch (rich.type) {
case 'RICH_TEXT_NODE_TYPE_AT':
Get.toNamed('/member?mid=${rich.rid}');
// case 'RICH_TEXT_NODE_TYPE_TOPIC':
default:
if (rich.jumpUrl != null) {
PiliScheme.routePushFromUrl(
rich.jumpUrl!,
);
}
}
},
);
}
case 'TEXT_NODE_TYPE_FORMULA' when (item.formula != null):
return TextSpan(
children: [
WidgetSpan(
child: CachedNetworkSVGImage(
height: 65,
'https://api.bilibili.com/x/web-frontend/mathjax/tex?formula=${Uri.encodeComponent(item.formula!.latexContent!)}',
colorFilter: ColorFilter.mode(
colorScheme.onSurfaceVariant,
BlendMode.srcIn,
),
alignment: Alignment.centerLeft,
placeholderBuilder: (_) =>
const SizedBox.shrink(),
),
),
],
);
default:
return _getSpan(
item.word,
isQuote ? colorScheme.onSurfaceVariant : null,
);
}
}).toList()),
);
if (isQuote) {
widget = Container(
@@ -167,7 +165,8 @@ class OpusContent extends StatelessWidget {
final height = width == null || pic.height == null
? null
: width * pic.height! / pic.width!;
return Hero(
return SelectionContainer.disabled(
child: Hero(
tag: pic.url!,
child: GestureDetector(
onTap: () {
@@ -192,42 +191,42 @@ class OpusContent extends StatelessWidget {
),
),
),
);
));
} else {
return imageView(
maxWidth,
element.pic!.pics!
.map(
(e) => ImageModel(width: 1, height: 1, url: e.url!))
.toList());
return SelectionContainer.disabled(
child: imageView(
maxWidth,
element.pic!.pics!
.map((e) =>
ImageModel(width: 1, height: 1, url: e.url!))
.toList()));
}
case 3 when (element.line != null):
return CachedNetworkImage(
return SelectionContainer.disabled(
child: CachedNetworkImage(
width: maxWidth,
fit: BoxFit.contain,
height: element.line!.pic!.height?.toDouble(),
imageUrl: Utils.thumbnailImgUrl(element.line!.pic!.url!),
);
));
case 5 when (element.list != null):
return SelectionArea(
child: Text.rich(
TextSpan(
children: element.list!.items?.indexed.map((entry) {
return TextSpan(
children: [
const WidgetSpan(
child: Icon(MdiIcons.circleMedium),
alignment: PlaceholderAlignment.middle,
),
...entry.$2.nodes!.map((item) {
return _getSpan(item.word);
}),
if (entry.$1 < element.list!.items!.length - 1)
const TextSpan(text: '\n'),
],
);
}).toList(),
),
return Text.rich(
TextSpan(
children: element.list!.items?.indexed.map((entry) {
return TextSpan(
children: [
const WidgetSpan(
child: Icon(MdiIcons.circleMedium),
alignment: PlaceholderAlignment.middle,
),
...entry.$2.nodes!.map((item) {
return _getSpan(item.word);
}),
if (entry.$1 < element.list!.items!.length - 1)
const TextSpan(text: '\n'),
],
);
}).toList(),
),
);
case 6:
@@ -528,7 +527,7 @@ class OpusContent extends StatelessWidget {
),
);
case 7 when (element.code != null):
final Highlight highlight = Highlight()
final highlight = Highlight()
..registerLanguages(builtinAllLanguages);
final HighlightResult result = highlight.highlightAuto(
element.code!.content!,
@@ -539,7 +538,7 @@ class OpusContent extends StatelessWidget {
.replaceAll('language-', '')
.replaceAll('like', ''),
]);
final TextSpanRenderer renderer = TextSpanRenderer(
final renderer = TextSpanRenderer(
const TextStyle(), builtinAllThemes['github']!);
result.render(renderer);
return Container(
@@ -549,40 +548,34 @@ class OpusContent extends StatelessWidget {
color: colorScheme.onInverseSurface,
),
width: double.infinity,
child: SelectionArea(child: Text.rich(renderer.span!)),
child: Text.rich(renderer.span!),
);
default:
debugPrint('unknown type ${element.paraType}');
if (element.text?.nodes?.isNotEmpty == true) {
return SelectionArea(
child: Text.rich(
textAlign: element.align == 1 ? TextAlign.center : null,
TextSpan(
children: element.text!.nodes!
.map<TextSpan>((item) => _getSpan(item.word))
.toList()),
),
return Text.rich(
textAlign: element.align == 1 ? TextAlign.center : null,
TextSpan(
children: element.text!.nodes!
.map<TextSpan>((item) => _getSpan(item.word))
.toList()),
);
}
return SelectionArea(
child: Text(
'不支持的类型 (${element.paraType})',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
return Text(
'不支持的类型 (${element.paraType})',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
);
}
} catch (e) {
return SelectionArea(
child: Text(
'错误的类型 $e',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
return Text(
'错误的类型 $e',
style: const TextStyle(
fontWeight: FontWeight.bold,
color: Colors.red,
),
);
}
@@ -597,7 +590,7 @@ Widget moduleBlockedItem(
BoxDecoration? bgImg() {
return moduleBlocked.bgImg == null
? null
: BoxDecoration(
: (BoxDecoration(
image: DecorationImage(
fit: BoxFit.fill,
image: CachedNetworkImageProvider(
@@ -608,7 +601,7 @@ Widget moduleBlockedItem(
),
),
),
);
));
}
Widget icon(double width) {
@@ -690,7 +683,8 @@ Widget moduleBlockedItem(
),
);
}
return Container(
return SelectionContainer.disabled(
child: Container(
decoration: bgImg(),
padding: const EdgeInsets.all(12),
child: Row(
@@ -726,7 +720,7 @@ Widget moduleBlockedItem(
),
],
),
);
));
}
Widget opusCollection(ThemeData theme, ModuleCollection item) {

View File

@@ -25,13 +25,14 @@ class ReadOpus extends StatelessWidget {
try {
final item = ops![index];
if (item.insert is String) {
return SelectableText(item.insert);
return Text(item.insert);
}
if (item.insert is Insert) {
InsertCard card = item.insert.card;
if (card.url?.isNotEmpty == true) {
return GestureDetector(
return SelectionContainer.disabled(
child: GestureDetector(
onTap: () {
switch (item.attributes?.clazz) {
case 'article-card card':
@@ -60,7 +61,7 @@ class ReadOpus extends StatelessWidget {
imageUrl: Utils.thumbnailImgUrl(card.url, 60),
),
),
);
));
}
}