mirror of
https://github.com/bggRGjQaUbCoE/PiliPlus.git
synced 2026-05-26 11:08:44 +00:00
show article heading
Closes #1338 Signed-off-by: bggRGjQaUbCoE <githubaccount56556@proton.me>
This commit is contained in:
@@ -11,6 +11,7 @@ class ArticleContentModel {
|
|||||||
LinkCard? linkCard;
|
LinkCard? linkCard;
|
||||||
Code? code;
|
Code? code;
|
||||||
L1st? list;
|
L1st? list;
|
||||||
|
Text? heading;
|
||||||
|
|
||||||
ArticleContentModel.fromJson(Map<String, dynamic> json) {
|
ArticleContentModel.fromJson(Map<String, dynamic> json) {
|
||||||
align = json['align'];
|
align = json['align'];
|
||||||
@@ -24,6 +25,7 @@ class ArticleContentModel {
|
|||||||
: LinkCard.fromJson(json['link_card']);
|
: LinkCard.fromJson(json['link_card']);
|
||||||
code = json['code'] == null ? null : Code.fromJson(json['code']);
|
code = json['code'] == null ? null : Code.fromJson(json['code']);
|
||||||
list = json['list'] == null ? null : L1st.fromJson(json['list']);
|
list = json['list'] == null ? null : L1st.fromJson(json['list']);
|
||||||
|
heading = json['heading'] == null ? null : Text.fromJson(json['heading']);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import 'package:PiliPlus/http/constants.dart';
|
|||||||
import 'package:PiliPlus/models/common/image_preview_type.dart';
|
import 'package:PiliPlus/models/common/image_preview_type.dart';
|
||||||
import 'package:PiliPlus/models/common/image_type.dart';
|
import 'package:PiliPlus/models/common/image_type.dart';
|
||||||
import 'package:PiliPlus/models/dynamics/article_content_model.dart'
|
import 'package:PiliPlus/models/dynamics/article_content_model.dart'
|
||||||
show ArticleContentModel, Rich, Style, Word;
|
show ArticleContentModel, Rich, Style, Word, Node;
|
||||||
import 'package:PiliPlus/models/dynamics/result.dart';
|
import 'package:PiliPlus/models/dynamics/result.dart';
|
||||||
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
|
import 'package:PiliPlus/pages/dynamics/widgets/vote.dart';
|
||||||
import 'package:PiliPlus/utils/app_scheme.dart';
|
import 'package:PiliPlus/utils/app_scheme.dart';
|
||||||
@@ -19,7 +19,7 @@ import 'package:cached_network_svg_image/cached_network_svg_image.dart';
|
|||||||
import 'package:flutter/foundation.dart' show kDebugMode;
|
import 'package:flutter/foundation.dart' show kDebugMode;
|
||||||
import 'package:flutter/gestures.dart';
|
import 'package:flutter/gestures.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:get/get.dart' hide ContextExtensionss;
|
import 'package:get/get.dart' hide ContextExtensionss, Node;
|
||||||
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
import 'package:material_design_icons_flutter/material_design_icons_flutter.dart';
|
||||||
import 'package:re_highlight/languages/all.dart';
|
import 'package:re_highlight/languages/all.dart';
|
||||||
import 'package:re_highlight/re_highlight.dart';
|
import 'package:re_highlight/re_highlight.dart';
|
||||||
@@ -36,6 +36,76 @@ class OpusContent extends StatelessWidget {
|
|||||||
required this.maxWidth,
|
required this.maxWidth,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static InlineSpan _node2Widget({
|
||||||
|
required Node item,
|
||||||
|
required ColorScheme colorScheme,
|
||||||
|
bool isQuote = false,
|
||||||
|
}) {
|
||||||
|
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):
|
||||||
|
final latex = item.formula!.latexContent!;
|
||||||
|
return WidgetSpan(
|
||||||
|
child: CachedNetworkSVGImage(
|
||||||
|
cacheKey: latex,
|
||||||
|
semanticsLabel: latex,
|
||||||
|
height: 65,
|
||||||
|
'${HttpString.apiBaseUrl}/x/web-frontend/mathjax/tex?formula=${Uri.encodeComponent(latex)}',
|
||||||
|
colorFilter: ColorFilter.mode(
|
||||||
|
colorScheme.onSurfaceVariant,
|
||||||
|
BlendMode.srcIn,
|
||||||
|
),
|
||||||
|
alignment: Alignment.centerLeft,
|
||||||
|
placeholderBuilder: (_) => Text(latex),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
default:
|
||||||
|
return _getSpan(
|
||||||
|
item.word,
|
||||||
|
isQuote ? colorScheme.onSurfaceVariant : null,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static TextStyle _getStyle(Style? style, [Color? color, double? fontSize]) =>
|
static TextStyle _getStyle(Style? style, [Color? color, double? fontSize]) =>
|
||||||
TextStyle(
|
TextStyle(
|
||||||
decoration: style?.strikethrough == true
|
decoration: style?.strikethrough == true
|
||||||
@@ -79,71 +149,12 @@ class OpusContent extends StatelessWidget {
|
|||||||
Widget widget = SelectableText.rich(
|
Widget widget = SelectableText.rich(
|
||||||
textAlign: element.align == 1 ? TextAlign.center : null,
|
textAlign: element.align == 1 ? TextAlign.center : null,
|
||||||
TextSpan(
|
TextSpan(
|
||||||
children: element.text?.nodes?.map((item) {
|
children: element.text?.nodes
|
||||||
switch (item.type) {
|
?.map(
|
||||||
case 'TEXT_NODE_TYPE_RICH' when (item.rich != null):
|
(item) =>
|
||||||
Rich rich = item.rich!;
|
_node2Widget(item: item, colorScheme: colorScheme),
|
||||||
switch (rich.type) {
|
)
|
||||||
case 'RICH_TEXT_NODE_TYPE_EMOJI':
|
.toList(),
|
||||||
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):
|
|
||||||
final latex = item.formula!.latexContent!;
|
|
||||||
return WidgetSpan(
|
|
||||||
child: CachedNetworkSVGImage(
|
|
||||||
cacheKey: latex,
|
|
||||||
semanticsLabel: latex,
|
|
||||||
height: 65,
|
|
||||||
'${HttpString.apiBaseUrl}/x/web-frontend/mathjax/tex?formula=${Uri.encodeComponent(latex)}',
|
|
||||||
colorFilter: ColorFilter.mode(
|
|
||||||
colorScheme.onSurfaceVariant,
|
|
||||||
BlendMode.srcIn,
|
|
||||||
),
|
|
||||||
alignment: Alignment.centerLeft,
|
|
||||||
placeholderBuilder: (_) => Text(latex),
|
|
||||||
),
|
|
||||||
);
|
|
||||||
default:
|
|
||||||
return _getSpan(
|
|
||||||
item.word,
|
|
||||||
isQuote ? colorScheme.onSurfaceVariant : null,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}).toList(),
|
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (isQuote) {
|
if (isQuote) {
|
||||||
@@ -586,6 +597,16 @@ class OpusContent extends StatelessWidget {
|
|||||||
width: double.infinity,
|
width: double.infinity,
|
||||||
child: SelectableText.rich(renderer.span!),
|
child: SelectableText.rich(renderer.span!),
|
||||||
);
|
);
|
||||||
|
case 8 when (element.heading?.nodes?.isNotEmpty == true):
|
||||||
|
return SelectableText.rich(
|
||||||
|
TextSpan(
|
||||||
|
children: element.heading!.nodes!
|
||||||
|
.map(
|
||||||
|
(e) => _node2Widget(item: e, colorScheme: colorScheme),
|
||||||
|
)
|
||||||
|
.toList(),
|
||||||
|
),
|
||||||
|
);
|
||||||
default:
|
default:
|
||||||
if (kDebugMode) debugPrint('unknown type ${element.paraType}');
|
if (kDebugMode) debugPrint('unknown type ${element.paraType}');
|
||||||
if (element.text?.nodes?.isNotEmpty == true) {
|
if (element.text?.nodes?.isNotEmpty == true) {
|
||||||
|
|||||||
Reference in New Issue
Block a user