diff --git a/lib/http/retry_interceptor.dart b/lib/http/retry_interceptor.dart index 157b4e1ae..62461064b 100644 --- a/lib/http/retry_interceptor.dart +++ b/lib/http/retry_interceptor.dart @@ -52,9 +52,9 @@ class RetryInterceptor extends Interceptor { case DioExceptionType.sendTimeout: case DioExceptionType.unknown: if ((err.requestOptions.extra['_rt'] ??= 0) < _count && - err.error - is! TransportConnectionException // 网络中断, 此时请求可能已经被服务器所接收 - ) { + err.error + is! TransportConnectionException // 网络中断, 此时请求可能已经被服务器所接收 + ) { Future.delayed( Duration( milliseconds: ++err.requestOptions.extra['_rt'] * _delay, diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index 149d7bbfc..77d848ea6 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -64,7 +64,7 @@ class DynamicsDataModel { continue; } if (enableFilter) { - if (item.orig case DynamicItemModel orig) { + if (item.orig case final orig?) { if (banWordForDyn.hasMatch(_getMatchText(orig))) { continue; } diff --git a/lib/pages/article/widgets/opus_content.dart b/lib/pages/article/widgets/opus_content.dart index c9822f1cc..3c856f68a 100644 --- a/lib/pages/article/widgets/opus_content.dart +++ b/lib/pages/article/widgets/opus_content.dart @@ -240,7 +240,7 @@ class OpusContent extends StatelessWidget { if (item.word != null) { return _getSpan(item.word); } - if (item.rich case Rich rich) { + if (item.rich case final rich?) { final hasUrl = rich.jumpUrl?.isNotEmpty == true; return TextSpan( text: '${hasUrl ? '\u{1F517}' : ''}${rich.text}', @@ -633,6 +633,8 @@ Widget moduleBlockedItem( ModuleBlocked moduleBlocked, double maxWidth, ) { + late final isDarkMode = Get.isDarkMode; + BoxDecoration? bgImg() { return moduleBlocked.bgImg == null ? null @@ -641,7 +643,7 @@ Widget moduleBlockedItem( fit: BoxFit.fill, image: CachedNetworkImageProvider( ImageUtil.thumbnailUrl( - Get.isDarkMode + isDarkMode ? moduleBlocked.bgImg!.imgDark : moduleBlocked.bgImg!.imgDay, ), @@ -655,9 +657,7 @@ Widget moduleBlockedItem( width: width, fit: BoxFit.contain, imageUrl: ImageUtil.thumbnailUrl( - Get.isDarkMode - ? moduleBlocked.icon!.imgDark - : moduleBlocked.icon!.imgDay, + isDarkMode ? moduleBlocked.icon!.imgDark : moduleBlocked.icon!.imgDay, ), ); } @@ -672,7 +672,7 @@ Widget moduleBlockedItem( padding: padding, tapTargetSize: MaterialTapTargetSize.shrinkWrap, visualDensity: visualDensity, - backgroundColor: Get.isDarkMode + backgroundColor: isDarkMode ? const Color(0xFF8F0030) : const Color(0xFFFF6699), foregroundColor: Colors.white, diff --git a/lib/pages/common/publish/common_rich_text_pub_page.dart b/lib/pages/common/publish/common_rich_text_pub_page.dart index 623fd3fce..df678005a 100644 --- a/lib/pages/common/publish/common_rich_text_pub_page.dart +++ b/lib/pages/common/publish/common_rich_text_pub_page.dart @@ -61,10 +61,8 @@ abstract class CommonRichTextPubPageState @override void dispose() { - if (hasPub) { - for (var i in pathList) { - File(i).delSync(); - } + for (var i in pathList) { + File(i).delSync(); } super.dispose(); } diff --git a/lib/pages/dynamics/widgets/additional_panel.dart b/lib/pages/dynamics/widgets/additional_panel.dart index efe543fb1..a0e2e300a 100644 --- a/lib/pages/dynamics/widgets/additional_panel.dart +++ b/lib/pages/dynamics/widgets/additional_panel.dart @@ -14,759 +14,680 @@ import 'package:flutter_smart_dialog/flutter_smart_dialog.dart'; import 'package:get/get.dart'; Widget addWidget( - ThemeData theme, - DynamicItemModel item, BuildContext context, { - floor = 1, + required int floor, + required ThemeData theme, + required dynamic idStr, + required DynamicAddModel additional, }) { - final type = item.modules.moduleDynamic?.additional?.type; + final type = additional.type; late final Color bgColor = floor == 1 ? theme.dividerColor.withValues(alpha: 0.08) : theme.colorScheme.surface; + late final borderRadius = floor == 1 ? null : StyleString.mdRadius; + Widget? child; try { switch (type) { // 转发的投稿 case 'ADDITIONAL_TYPE_UGC': - final ugc = item.modules.moduleDynamic!.additional!.ugc!; - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - borderRadius: borderRadius, - color: bgColor, - child: InkWell( - borderRadius: borderRadius, - onTap: ugc.jumpUrl == null - ? null - : () => PiliScheme.routePushFromUrl(ugc.jumpUrl!), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, + final ugc = additional.ugc!; + child = InkWell( + borderRadius: borderRadius, + onTap: ugc.jumpUrl == null + ? null + : () => PiliScheme.routePushFromUrl(ugc.jumpUrl!), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + child: Row( + children: [ + NetworkImgLayer( + width: 120, + height: 75, + src: ugc.cover, ), - child: Row( - children: [ - NetworkImgLayer( - width: 120, - height: 75, - src: ugc.cover, - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - ugc.title!, - maxLines: 2, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - Text( - ugc.descSecond!, - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: theme.textTheme.labelMedium!.fontSize, - ), - ), - ], + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + ugc.title!, + maxLines: 2, + overflow: TextOverflow.ellipsis, ), - ), - ], + const SizedBox(height: 4), + Text( + ugc.descSecond!, + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: theme.textTheme.labelMedium!.fontSize, + ), + ), + ], + ), ), - ), + ], ), ), ); case 'ADDITIONAL_TYPE_RESERVE': - final reserve = item.modules.moduleDynamic!.additional!.reserve!; - late final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return reserve.state != -1 - ? reserve.title != null - ? Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: InkWell( - onTap: () {}, - borderRadius: borderRadius, - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 10, + final reserve = additional.reserve!; + if (reserve.state != -1 && reserve.title != null) { + child = InkWell( + onTap: () {}, + borderRadius: borderRadius, + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), + child: Row( + children: [ + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + reserve.title!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + const SizedBox(height: 1), + Text.rich( + TextSpan( + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: 13, ), - child: Row( - children: [ - Expanded( - child: Column( - crossAxisAlignment: - CrossAxisAlignment.start, - children: [ - Text( - reserve.title!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - const SizedBox(height: 1), - Text.rich( - TextSpan( - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: 13, - ), - children: [ - if (reserve - .desc1 - ?.text - ?.isNotEmpty == - true) - TextSpan( - text: reserve.desc1!.text, - ), - if (reserve - .desc2 - ?.text - ?.isNotEmpty == - true) - TextSpan( - text: - ' ${reserve.desc2!.text}', - ), - if (reserve - .desc3 - ?.text - ?.isNotEmpty == - true) ...[ - const TextSpan(text: '\n'), - WidgetSpan( - alignment: - PlaceholderAlignment.middle, - child: Icon( - size: 17, - Icons.card_giftcard, - color: - theme.colorScheme.primary, - ), - ), - TextSpan( - text: ' ${reserve.desc3!.text}', - style: TextStyle( - color: - theme.colorScheme.primary, - ), - recognizer: - reserve.desc3!.jumpUrl == - null - ? null - : (TapGestureRecognizer() - ..onTap = () { - Get.toNamed( - '/webview', - parameters: { - 'url': reserve - .desc3! - .jumpUrl!, - }, - ); - }), - ), - ], - ], - ), - ), - ], + children: [ + if (reserve.desc1?.text?.isNotEmpty == true) + TextSpan( + text: reserve.desc1!.text, + ), + if (reserve.desc2?.text?.isNotEmpty == true) + TextSpan( + text: ' ${reserve.desc2!.text}', + ), + if (reserve.desc3?.text?.isNotEmpty == true) ...[ + const TextSpan(text: '\n'), + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + size: 17, + Icons.card_giftcard, + color: theme.colorScheme.primary, ), ), - if (reserve.button != null) ...[ - const SizedBox(width: 10), - Builder( - builder: (context) { - final btn = reserve.button!; - final isReserved = btn.status == btn.type; - final bool canJump = btn.jumpUrl != null; - return FilledButton.tonal( - style: FilledButton.styleFrom( - foregroundColor: canJump - ? null - : isReserved - ? theme.colorScheme.onSurface - .withValues(alpha: 0.38) - : null, - backgroundColor: canJump - ? null - : isReserved - ? theme.colorScheme.onSurface - .withValues(alpha: 0.12) - : null, - visualDensity: VisualDensity.compact, - padding: const EdgeInsets.symmetric( - horizontal: 16, - ), - tapTargetSize: - MaterialTapTargetSize.shrinkWrap, - ), - onPressed: canJump - ? () => PiliScheme.routePushFromUrl( - btn.jumpUrl!, - ) - : btn.disable == 1 - ? null - : () async { - var res = - await DynamicsHttp.dynReserve( - reserveId: reserve.rid, - curBtnStatus: btn.status, - dynamicIdStr: item.idStr, - reserveTotal: - reserve.reserveTotal, - ); - if (res['status']) { - DynReserveData data = - res['data']; - reserve - ..desc2?.text = - data.descUpdate - ..reserveTotal = - data.reserveUpdate - ..button!.status = - data.finalBtnStatus; - if (context.mounted) { - (context as Element?) - ?.markNeedsBuild(); - } - } else { - SmartDialog.showToast( - res['msg'], - ); - } + TextSpan( + text: ' ${reserve.desc3!.text}', + style: TextStyle( + color: theme.colorScheme.primary, + ), + recognizer: reserve.desc3!.jumpUrl == null + ? null + : (TapGestureRecognizer() + ..onTap = () { + Get.toNamed( + '/webview', + parameters: { + 'url': reserve.desc3!.jumpUrl!, }, - child: Text( - btn.jumpText != null - ? btn.jumpText! - : isReserved - ? btn.checkText! - : btn.uncheckText!, - ), - ); - }, - ), - ], + ); + }), + ), ], - ), + ], ), ), - ), - ) - : const SizedBox.shrink() - : const SizedBox.shrink(); - case 'ADDITIONAL_TYPE_UPOWER_LOTTERY': - final content = item.modules.moduleDynamic!.additional!.upowerLottery!; - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: InkWell( - borderRadius: borderRadius, - onTap: content.jumpUrl == null - ? null - : () => PiliScheme.routePushFromUrl(content.jumpUrl!), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - child: Row( - children: [ - Expanded( - child: Column( - spacing: 2, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (content.title?.isNotEmpty == true) - Text(content.title!), - if (content.hint?.text?.isNotEmpty == true) - Text( - content.hint!.text!, - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: 13, - ), - ), - if (content.desc?.text?.isNotEmpty == true) - Text.rich( - TextSpan( - children: [ - WidgetSpan( - alignment: PlaceholderAlignment.middle, - child: Icon( - size: 17, - Icons.card_giftcard, - color: theme.colorScheme.primary, - ), - ), - TextSpan( - text: ' ${content.desc!.text!}', - style: TextStyle( - color: theme.colorScheme.primary, - fontSize: 13, - ), - recognizer: content.desc!.jumpUrl == null - ? null - : (TapGestureRecognizer() - ..onTap = () { - Get.toNamed( - '/webview', - parameters: { - 'url': content.desc!.jumpUrl!, - }, - ); - }), - ), - ], - ), - ), - ], - ), + ], ), - if (content.button != null) ...[ - const SizedBox(width: 10), - FilledButton.tonal( - onPressed: content.button!.jumpUrl == null - ? null - : () => PiliScheme.routePushFromUrl( - content.button!.jumpUrl!, - ), - style: FilledButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(6)), + ), + if (reserve.button != null) ...[ + const SizedBox(width: 10), + Builder( + builder: (context) { + final btn = reserve.button!; + final isReserved = btn.status == btn.type; + final bool canJump = btn.jumpUrl != null; + return FilledButton.tonal( + style: FilledButton.styleFrom( + foregroundColor: canJump + ? null + : isReserved + ? theme.colorScheme.onSurface.withValues( + alpha: 0.38, + ) + : null, + backgroundColor: canJump + ? null + : isReserved + ? theme.colorScheme.onSurface.withValues( + alpha: 0.12, + ) + : null, + visualDensity: VisualDensity.compact, + padding: const EdgeInsets.symmetric( + horizontal: 16, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - padding: const EdgeInsets.symmetric(horizontal: 10), - visualDensity: const VisualDensity( - horizontal: -2, - vertical: -3, + onPressed: canJump + ? () => PiliScheme.routePushFromUrl( + btn.jumpUrl!, + ) + : btn.disable == 1 + ? null + : () async { + var res = await DynamicsHttp.dynReserve( + reserveId: reserve.rid, + curBtnStatus: btn.status, + dynamicIdStr: idStr, + reserveTotal: reserve.reserveTotal, + ); + if (res['status']) { + DynReserveData data = res['data']; + reserve + ..desc2?.text = data.descUpdate + ..reserveTotal = data.reserveUpdate + ..button!.status = data.finalBtnStatus; + if (context.mounted) { + (context as Element?)?.markNeedsBuild(); + } + } else { + SmartDialog.showToast( + res['msg'], + ); + } + }, + child: Text( + btn.jumpText != null + ? btn.jumpText! + : isReserved + ? btn.checkText! + : btn.uncheckText!, ), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: Text( - content.button!.jumpStyle?.text ?? - content.button!.check?.text ?? - '', - ), - ), - ], + ); + }, + ), ], - ), + ], ), ), + ); + } + return const SizedBox.shrink(); + + case 'ADDITIONAL_TYPE_UPOWER_LOTTERY': + final content = additional.upowerLottery!; + child = InkWell( + borderRadius: borderRadius, + onTap: content.jumpUrl == null + ? null + : () => PiliScheme.routePushFromUrl(content.jumpUrl!), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + Expanded( + child: Column( + spacing: 2, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (content.title?.isNotEmpty == true) + Text(content.title!), + if (content.hint?.text?.isNotEmpty == true) + Text( + content.hint!.text!, + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: 13, + ), + ), + if (content.desc?.text?.isNotEmpty == true) + Text.rich( + TextSpan( + children: [ + WidgetSpan( + alignment: PlaceholderAlignment.middle, + child: Icon( + size: 17, + Icons.card_giftcard, + color: theme.colorScheme.primary, + ), + ), + TextSpan( + text: ' ${content.desc!.text!}', + style: TextStyle( + color: theme.colorScheme.primary, + fontSize: 13, + ), + recognizer: content.desc!.jumpUrl == null + ? null + : (TapGestureRecognizer() + ..onTap = () { + Get.toNamed( + '/webview', + parameters: { + 'url': content.desc!.jumpUrl!, + }, + ); + }), + ), + ], + ), + ), + ], + ), + ), + if (content.button != null) ...[ + const SizedBox(width: 10), + FilledButton.tonal( + onPressed: content.button!.jumpUrl == null + ? null + : () => PiliScheme.routePushFromUrl( + content.button!.jumpUrl!, + ), + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -3, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text( + content.button!.jumpStyle?.text ?? + content.button!.check?.text ?? + '', + ), + ), + ], + ], + ), ), ); + // 商品 case 'ADDITIONAL_TYPE_GOODS': - final content = item.modules.moduleDynamic!.additional!.goods!; + final content = additional.goods!; if (content.items?.isNotEmpty == true) { - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: content.items!.map((e) { - return InkWell( - borderRadius: borderRadius, - onTap: () => PiliScheme.routePushFromUrl(e.jumpUrl!), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - child: Row( - children: [ - if (e.cover?.isNotEmpty == true) ...[ - NetworkImgLayer( - width: 45, - height: 45, - src: e.cover, - radius: 6, + child = Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: content.items!.map((e) { + return InkWell( + borderRadius: borderRadius, + onTap: () => PiliScheme.routePushFromUrl(e.jumpUrl!), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + child: Row( + children: [ + if (e.cover?.isNotEmpty == true) ...[ + NetworkImgLayer( + width: 45, + height: 45, + src: e.cover, + radius: 6, + ), + const SizedBox(width: 10), + ], + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + e.name!, + maxLines: 1, + overflow: TextOverflow.ellipsis, ), - const SizedBox(width: 10), - ], - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - e.name!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - if (e.price?.isNotEmpty == true) - Text.rich( + if (e.price?.isNotEmpty == true) + Text.rich( + TextSpan( + children: [ TextSpan( - children: [ - TextSpan( - text: '${e.price}', - style: TextStyle( - color: theme.colorScheme.primary, - ), - ), - const TextSpan( - text: ' 起', - style: TextStyle(fontSize: 12), - ), - ], + text: '${e.price}', + style: TextStyle( + color: theme.colorScheme.primary, + ), ), - ), - ], - ), - ), - if (e.jumpDesc?.isNotEmpty == true) ...[ - const SizedBox(width: 10), - FilledButton.tonal( - onPressed: () => - PiliScheme.routePushFromUrl(e.jumpUrl!), - style: FilledButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all( - Radius.circular(6), - ), + const TextSpan( + text: ' 起', + style: TextStyle(fontSize: 12), + ), + ], ), - padding: const EdgeInsets.symmetric( - horizontal: 10, - ), - visualDensity: const VisualDensity( - horizontal: -2, - vertical: -3, - ), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, ), - child: Text(e.jumpDesc!), - ), ], - ], + ), ), - ), - ); - }).toList(), - ), - ), + if (e.jumpDesc?.isNotEmpty == true) ...[ + const SizedBox(width: 10), + FilledButton.tonal( + onPressed: () => + PiliScheme.routePushFromUrl(e.jumpUrl!), + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all( + Radius.circular(6), + ), + ), + padding: const EdgeInsets.symmetric( + horizontal: 10, + ), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -3, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text(e.jumpDesc!), + ), + ], + ], + ), + ), + ); + }).toList(), ); } return const SizedBox.shrink(); + case 'ADDITIONAL_TYPE_VOTE': - final vote = item.modules.moduleDynamic!.additional!.vote!; - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: InkWell( - borderRadius: borderRadius, - onTap: () => showVoteDialog( - context, - vote.voteId!, - item.idStr is int - ? item.idStr - : item.idStr is String - ? int.parse(item.idStr) - : null, - ), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, + final vote = additional.vote!; + child = InkWell( + borderRadius: borderRadius, + onTap: () => showVoteDialog( + context, + vote.voteId!, + idStr is int + ? idStr + : idStr is String + ? int.parse(idStr) + : null, + ), + child: Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12, + vertical: 8, + ), + child: Row( + children: [ + Container( + decoration: BoxDecoration( + color: floor == 1 + ? theme.colorScheme.surface + : theme.dividerColor.withValues(alpha: 0.08), + borderRadius: const BorderRadius.all( + Radius.circular(8), + ), + ), + width: 70, + height: 50, + child: Icon( + Icons.bar_chart_rounded, + color: theme.colorScheme.onSurfaceVariant, + ), ), - child: Row( - children: [ - Container( - decoration: BoxDecoration( - color: floor == 1 - ? theme.colorScheme.surface - : theme.dividerColor.withValues(alpha: 0.08), - borderRadius: const BorderRadius.all( - Radius.circular(8), + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + vote.desc!, + maxLines: 1, + overflow: TextOverflow.ellipsis, + ), + Text( + '${NumUtil.numFormat(vote.joinNum)}人参与', + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.outline, ), ), - width: 70, - height: 50, - child: Icon( - Icons.bar_chart_rounded, - color: theme.colorScheme.onSurfaceVariant, - ), - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - vote.desc!, - maxLines: 1, - overflow: TextOverflow.ellipsis, - ), - Text( - '${NumUtil.numFormat(vote.joinNum)}人参与', - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: TextStyle( - fontSize: 13, - color: theme.colorScheme.outline, - ), - ), - ], - ), - ), - const SizedBox(width: 10), - FilledButton.tonal( - onPressed: () => showVoteDialog( - context, - vote.voteId!, - item.idStr is int - ? item.idStr - : item.idStr is String - ? int.parse(item.idStr) - : null, - ), - style: FilledButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(6)), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - visualDensity: const VisualDensity( - horizontal: -2, - vertical: -3, - ), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: const Text('参与'), - ), - ], + ], + ), ), - ), + const SizedBox(width: 10), + FilledButton.tonal( + onPressed: () => showVoteDialog( + context, + vote.voteId!, + idStr is int + ? idStr + : idStr is String + ? int.parse(idStr) + : null, + ), + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -3, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: const Text('参与'), + ), + ], ), ), ); + case 'ADDITIONAL_TYPE_COMMON': - final content = item.modules.moduleDynamic!.additional!.common!; - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: InkWell( - borderRadius: borderRadius, - onTap: content.jumpUrl == null - ? null - : () => PiliScheme.routePushFromUrl(content.jumpUrl!), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - child: Row( - children: [ - if (content.cover?.isNotEmpty == true) ...[ - NetworkImgLayer( - width: 45, - height: 45, - src: content.cover, - radius: 6, - ), - const SizedBox(width: 10), + final content = additional.common!; + child = InkWell( + borderRadius: borderRadius, + onTap: content.jumpUrl == null + ? null + : () => PiliScheme.routePushFromUrl(content.jumpUrl!), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + if (content.cover?.isNotEmpty == true) ...[ + NetworkImgLayer( + width: 45, + height: 45, + src: content.cover, + radius: 6, + ), + const SizedBox(width: 10), + ], + Expanded( + child: Column( + spacing: 2, + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (content.title?.isNotEmpty == true) + Text(content.title!), + if (content.desc1?.isNotEmpty == true) + Text( + content.desc1!, + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: 13, + ), + ), + if (content.desc2?.isNotEmpty == true) + Text( + content.desc2!, + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: 13, + ), + ), ], - Expanded( - child: Column( - spacing: 2, - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (content.title?.isNotEmpty == true) - Text(content.title!), - if (content.desc1?.isNotEmpty == true) - Text( - content.desc1!, - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: 13, - ), - ), - if (content.desc2?.isNotEmpty == true) - Text( - content.desc2!, - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: 13, - ), - ), - ], - ), + ), + ), + if (content.button?.jumpUrl?.isNotEmpty == true) ...[ + const SizedBox(width: 10), + FilledButton.tonal( + onPressed: () => PiliScheme.routePushFromUrl( + content.button!.jumpUrl!, ), - if (content.button?.jumpUrl?.isNotEmpty == true) ...[ - const SizedBox(width: 10), - FilledButton.tonal( - onPressed: () => PiliScheme.routePushFromUrl( - content.button!.jumpUrl!, - ), - style: FilledButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(6)), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - visualDensity: const VisualDensity( - horizontal: -2, - vertical: -3, - ), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: Text(content.button!.jumpStyle?.text ?? ''), + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), ), - ], - ], - ), - ), + padding: const EdgeInsets.symmetric(horizontal: 10), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -3, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text(content.button!.jumpStyle?.text ?? ''), + ), + ], + ], ), ), ); + case 'ADDITIONAL_TYPE_MATCH': - final content = item.modules.moduleDynamic!.additional!.match!; - final borderRadius = floor == 1 ? null : StyleString.mdRadius; - return Padding( - padding: const EdgeInsets.only(top: 6), - child: Material( - color: bgColor, - borderRadius: borderRadius, - child: InkWell( - borderRadius: borderRadius, - onTap: content.jumpUrl == null - ? null - : () => PiliScheme.routePushFromUrl(content.jumpUrl!), - child: Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12, - vertical: 8, - ), - child: Row( + final content = additional.match!; + child = InkWell( + borderRadius: borderRadius, + onTap: content.jumpUrl == null + ? null + : () => PiliScheme.routePushFromUrl(content.jumpUrl!), + child: Padding( + padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8), + child: Row( + children: [ + Column( + mainAxisSize: MainAxisSize.min, children: [ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - if (content.matchInfo?.title?.isNotEmpty == true) - Text( - content.matchInfo!.title!, - style: const TextStyle(fontSize: 13), - ), - if (content.matchInfo?.subTitle?.isNotEmpty == true) - Text( - content.matchInfo!.subTitle!, - style: TextStyle( - fontSize: 13, - color: theme.colorScheme.outline, - ), - ), - ], - ), - const Spacer(), - if (content.matchInfo?.leftTeam != null) ...[ - Column( - mainAxisSize: MainAxisSize.min, - children: [ - NetworkImgLayer( - width: 30, - height: 30, - src: content.matchInfo!.leftTeam!.pic, - ), - const SizedBox(height: 5), - Text( - content.matchInfo!.leftTeam!.name!, - style: const TextStyle(fontSize: 13), - ), - ], + if (content.matchInfo?.title?.isNotEmpty == true) + Text( + content.matchInfo!.title!, + style: const TextStyle(fontSize: 13), ), - const SizedBox(width: 16), - ], - Column( - children: [ - if (content.matchInfo?.centerTop?.isNotEmpty == true) - Container( - height: 35, - alignment: Alignment.center, - child: Text( - content.matchInfo!.centerTop!.join(' '), - style: const TextStyle( - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - if (content.matchInfo?.centerBottom?.isNotEmpty == true) - Text( - content.matchInfo!.centerBottom!, - style: TextStyle( - fontSize: 13, - color: theme.colorScheme.outline, - ), - ), - ], - ), - if (content.matchInfo?.rightTeam != null) ...[ - const SizedBox(width: 16), - Column( - mainAxisSize: MainAxisSize.min, - children: [ - NetworkImgLayer( - width: 30, - height: 30, - src: content.matchInfo!.rightTeam!.pic, - ), - const SizedBox(height: 5), - Text( - content.matchInfo!.rightTeam!.name!, - style: const TextStyle(fontSize: 13), - ), - ], - ), - ], - const Spacer(), - if (content.button != null) - FilledButton.tonal( - onPressed: () => PiliScheme.routePushFromUrl( - content.button!.jumpUrl!, + if (content.matchInfo?.subTitle?.isNotEmpty == true) + Text( + content.matchInfo!.subTitle!, + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.outline, ), - style: FilledButton.styleFrom( - shape: const RoundedRectangleBorder( - borderRadius: BorderRadius.all(Radius.circular(6)), - ), - padding: const EdgeInsets.symmetric(horizontal: 10), - visualDensity: const VisualDensity( - horizontal: -2, - vertical: -3, - ), - tapTargetSize: MaterialTapTargetSize.shrinkWrap, - ), - child: Text(content.button!.jumpStyle?.text ?? ''), ), ], ), - ), + const Spacer(), + if (content.matchInfo?.leftTeam != null) ...[ + Column( + mainAxisSize: MainAxisSize.min, + children: [ + NetworkImgLayer( + width: 30, + height: 30, + src: content.matchInfo!.leftTeam!.pic, + ), + const SizedBox(height: 5), + Text( + content.matchInfo!.leftTeam!.name!, + style: const TextStyle(fontSize: 13), + ), + ], + ), + const SizedBox(width: 16), + ], + Column( + children: [ + if (content.matchInfo?.centerTop?.isNotEmpty == true) + Container( + height: 35, + alignment: Alignment.center, + child: Text( + content.matchInfo!.centerTop!.join(' '), + style: const TextStyle( + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + if (content.matchInfo?.centerBottom?.isNotEmpty == true) + Text( + content.matchInfo!.centerBottom!, + style: TextStyle( + fontSize: 13, + color: theme.colorScheme.outline, + ), + ), + ], + ), + if (content.matchInfo?.rightTeam != null) ...[ + const SizedBox(width: 16), + Column( + mainAxisSize: MainAxisSize.min, + children: [ + NetworkImgLayer( + width: 30, + height: 30, + src: content.matchInfo!.rightTeam!.pic, + ), + const SizedBox(height: 5), + Text( + content.matchInfo!.rightTeam!.name!, + style: const TextStyle(fontSize: 13), + ), + ], + ), + ], + const Spacer(), + if (content.button case final button?) + FilledButton.tonal( + onPressed: () => + PiliScheme.routePushFromUrl(button.jumpUrl!), + style: FilledButton.styleFrom( + shape: const RoundedRectangleBorder( + borderRadius: BorderRadius.all(Radius.circular(6)), + ), + padding: const EdgeInsets.symmetric(horizontal: 10), + visualDensity: const VisualDensity( + horizontal: -2, + vertical: -3, + ), + tapTargetSize: MaterialTapTargetSize.shrinkWrap, + ), + child: Text(button.jumpStyle?.text ?? ''), + ), + ], ), ), ); - default: - if (kDebugMode) { - return Padding( - padding: const EdgeInsets.symmetric(horizontal: 12), - child: Text('additional panel\ntype: $type'), - ); - } - return const SizedBox.shrink(); + } + if (child != null) { + return Padding( + padding: const EdgeInsets.only(top: 6), + child: Material( + borderRadius: borderRadius, + color: bgColor, + child: child, + ), + ); + } else { + if (kDebugMode) { + return Padding( + padding: const EdgeInsets.symmetric(horizontal: 12), + child: Text('additional panel\ntype: $type'), + ); + } + return const SizedBox.shrink(); } } catch (e) { return Padding( @@ -774,7 +695,7 @@ Widget addWidget( child: SelectableText( ''' additional panel error -id: ${item.idStr} +id: $idStr type: $type err: $e''', ), diff --git a/lib/pages/dynamics/widgets/author_panel.dart b/lib/pages/dynamics/widgets/author_panel.dart index dd8d907e9..6e5877803 100644 --- a/lib/pages/dynamics/widgets/author_panel.dart +++ b/lib/pages/dynamics/widgets/author_panel.dart @@ -26,9 +26,9 @@ import 'package:get/get.dart' hide ContextExtensionss; class AuthorPanel extends StatelessWidget { final DynamicItemModel item; final Function? addBannedList; + final bool isSave; final bool isDetail; final ValueChanged? onRemove; - final bool isSave; final Function(bool isTop, dynamic dynId)? onSetTop; final VoidCallback? onBlock; @@ -43,10 +43,10 @@ class AuthorPanel extends StatelessWidget { this.onBlock, }); - Widget _buildAvatar() { - String? pendant = item.modules.moduleAuthor?.pendant?.image; + Widget _buildAvatar(ModuleAuthorModel moduleAuthor) { + String? pendant = moduleAuthor.pendant?.image; Widget avatar = PendantAvatar( - avatar: item.modules.moduleAuthor?.face, + avatar: moduleAuthor.face, size: pendant.isNullOrEmpty ? 40 : 34, officialType: null, // 已被注释 garbPendantImage: pendant, @@ -60,14 +60,15 @@ class AuthorPanel extends StatelessWidget { @override Widget build(BuildContext context) { final theme = Theme.of(context); - final pubTime = item.modules.moduleAuthor?.pubTs != null + final moduleAuthor = item.modules.moduleAuthor!; + final pubTime = moduleAuthor.pubTs != null ? isSave ? DateUtil.format( - item.modules.moduleAuthor!.pubTs, + moduleAuthor.pubTs, format: DateUtil.longFormatDs, ) - : DateUtil.dateFormat(item.modules.moduleAuthor!.pubTs) - : item.modules.moduleAuthor?.pubTime; + : DateUtil.dateFormat(moduleAuthor.pubTs) + : moduleAuthor.pubTime; return Stack( clipBehavior: Clip.none, alignment: Alignment.center, @@ -76,29 +77,29 @@ class AuthorPanel extends StatelessWidget { alignment: Alignment.centerLeft, child: GestureDetector( behavior: HitTestBehavior.opaque, - onTap: item.modules.moduleAuthor!.type == 'AUTHOR_TYPE_NORMAL' + onTap: moduleAuthor.type == 'AUTHOR_TYPE_NORMAL' ? () { feedBack(); Get.toNamed( - '/member?mid=${item.modules.moduleAuthor!.mid}', + '/member?mid=${moduleAuthor.mid}', ); } : null, child: Row( mainAxisSize: MainAxisSize.min, children: [ - _buildAvatar(), + _buildAvatar(moduleAuthor), const SizedBox(width: 10), Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - item.modules.moduleAuthor?.name ?? '', + moduleAuthor.name ?? '', style: TextStyle( color: - item.modules.moduleAuthor!.vip != null && - item.modules.moduleAuthor!.vip!.status > 0 && - item.modules.moduleAuthor!.vip!.type == 2 + moduleAuthor.vip != null && + moduleAuthor.vip!.status > 0 && + moduleAuthor.vip!.type == 2 ? theme.colorScheme.vipColor : theme.colorScheme.onSurface, fontSize: theme.textTheme.titleSmall!.fontSize, @@ -106,7 +107,7 @@ class AuthorPanel extends StatelessWidget { ), if (pubTime != null) Text( - '$pubTime${item.modules.moduleAuthor?.pubAction != null ? ' ${item.modules.moduleAuthor!.pubAction}' : ''}', + '$pubTime${moduleAuthor.pubAction != null ? ' ${moduleAuthor.pubAction}' : ''}', style: TextStyle( color: theme.colorScheme.outline, fontSize: theme.textTheme.labelSmall!.fontSize, @@ -155,7 +156,7 @@ class AuthorPanel extends StatelessWidget { _moreWidget(context), ], ) - : item.modules.moduleAuthor!.decorate != null + : moduleAuthor.decorate != null ? Row( mainAxisSize: MainAxisSize.min, children: [ @@ -165,48 +166,24 @@ class AuthorPanel extends StatelessWidget { children: [ CachedNetworkImage( height: 32, - imageUrl: item - .modules - .moduleAuthor! - .decorate! - .cardUrl - .http2https, + imageUrl: moduleAuthor.decorate!.cardUrl.http2https, ), - if (item - .modules - .moduleAuthor - ?.decorate - ?.fan - ?.numStr - ?.isNotEmpty == + if (moduleAuthor.decorate?.fan?.numStr?.isNotEmpty == true) Padding( padding: const EdgeInsets.only(right: 32), child: Text( - '${item.modules.moduleAuthor!.decorate!.fan!.numStr}', + '${moduleAuthor.decorate!.fan!.numStr}', style: TextStyle( height: 1, fontSize: 11, fontFamily: 'digital_id_num', color: - item - .modules - .moduleAuthor! - .decorate! - .fan - ?.color + moduleAuthor.decorate!.fan?.color ?.startsWith('#') == true - ? Color( - int.parse( - item - .modules - .moduleAuthor! - .decorate! - .fan! - .color! - .replaceFirst('#', '0xFF'), - ), + ? Utils.parseColor( + moduleAuthor.decorate!.fan!.color!, ) : null, ), @@ -250,7 +227,7 @@ class AuthorPanel extends StatelessWidget { if (bvid == null && item.orig != null) { bvid = getBvid( item.orig!.type, - item.orig?.modules.moduleDynamic?.major, + item.orig!.modules.moduleDynamic?.major, ); } } catch (_) {} @@ -264,6 +241,7 @@ class AuthorPanel extends StatelessWidget { ), builder: (context1) { final theme = Theme.of(context); + final moduleAuthor = item.modules.moduleAuthor!; return Padding( padding: EdgeInsets.only( bottom: MediaQuery.viewPaddingOf(context1).bottom, @@ -347,32 +325,13 @@ class AuthorPanel extends StatelessWidget { bool isDyn = item.basic!.commentType == 17; String id = isDyn ? item.idStr : item.basic!.ridStr!; int source = isDyn ? 11 : 2; - String title; - if (item.modules.moduleDynamic?.desc != null) { - title = item.modules.moduleDynamic!.desc!.text!; - } else if (item.modules.moduleDynamic?.major != null) { - title = item - .modules - .moduleDynamic! - .major! - .opus! - .summary! - .text!; - } else { - throw UnsupportedError( - 'error getting title: {"type": ${item.basic!.commentType}, "id": $id}', - ); - } + final moduleDynamic = item.modules.moduleDynamic!; + final title = + moduleDynamic.desc?.text ?? + moduleDynamic.major!.opus!.summary!.text!; String? thumb = isDyn - ? item.modules.moduleAuthor?.face - : item - .modules - .moduleDynamic - ?.major - ?.opus - ?.pics - ?.firstOrNull - ?.url; + ? moduleAuthor.face + : moduleDynamic.major?.opus?.pics?.firstOrNull?.url; PageUtils.pmShare( context, content: { @@ -381,9 +340,8 @@ class AuthorPanel extends StatelessWidget { "headline": "", "source": source, if (thumb?.isNotEmpty == true) "thumb": thumb, - "author": item.modules.moduleAuthor!.name, - "author_id": item.modules.moduleAuthor!.mid - .toString(), + "author": moduleAuthor.name, + "author_id": moduleAuthor.mid.toString(), }, ); } catch (e) { @@ -394,7 +352,7 @@ class AuthorPanel extends StatelessWidget { ), ListTile( title: Text( - '临时屏蔽:${item.modules.moduleAuthor?.name}', + '临时屏蔽:${moduleAuthor.name}', style: theme.textTheme.titleSmall, ), leading: const Icon(Icons.visibility_off_outlined, size: 19), @@ -403,16 +361,16 @@ class AuthorPanel extends StatelessWidget { onBlock?.call(); try { Get.find().tempBannedList.add( - item.modules.moduleAuthor!.mid!, + moduleAuthor.mid!, ); SmartDialog.showToast( - '已临时屏蔽${item.modules.moduleAuthor?.name}(${item.modules.moduleAuthor!.mid!}),重启恢复', + '已临时屏蔽${moduleAuthor.name}(${moduleAuthor.mid!}),重启恢复', ); } catch (_) {} }, minLeadingWidth: 0, ), - if (item.modules.moduleAuthor?.mid == Accounts.main.mid) ...[ + if (moduleAuthor.mid == Accounts.main.mid) ...[ ListTile( onTap: () { Get.back(); @@ -512,13 +470,13 @@ class AuthorPanel extends StatelessWidget { (reasonType, reasonDesc, banUid) { if (banUid) { VideoHttp.relationMod( - mid: item.modules.moduleAuthor!.mid!, + mid: moduleAuthor.mid!, act: 5, reSrc: 11, ); } return UserHttp.dynamicReport( - mid: item.modules.moduleAuthor!.mid, + mid: moduleAuthor.mid, dynId: item.idStr, reasonType: reasonType, ); diff --git a/lib/pages/dynamics/widgets/blocked_item.dart b/lib/pages/dynamics/widgets/blocked_item.dart index caa5c17c3..179a0b771 100644 --- a/lib/pages/dynamics/widgets/blocked_item.dart +++ b/lib/pages/dynamics/widgets/blocked_item.dart @@ -3,13 +3,13 @@ import 'package:PiliPlus/pages/article/widgets/opus_content.dart' show moduleBlockedItem; import 'package:flutter/material.dart'; -Widget blockedItem( - ThemeData theme, - ModuleBlocked moduleBlocked, { +Widget blockedItem({ + required ThemeData theme, + required ModuleBlocked blocked, required double maxWidth, }) { return Padding( padding: const EdgeInsets.symmetric(horizontal: 13, vertical: 1), - child: moduleBlockedItem(theme, moduleBlocked, maxWidth - 26), + child: moduleBlockedItem(theme, blocked, maxWidth - 26), ); } diff --git a/lib/pages/dynamics/widgets/content_panel.dart b/lib/pages/dynamics/widgets/content_panel.dart index 9aaf2ec77..af7a4b5b2 100644 --- a/lib/pages/dynamics/widgets/content_panel.dart +++ b/lib/pages/dynamics/widgets/content_panel.dart @@ -8,19 +8,26 @@ import 'package:flutter/material.dart'; import 'package:get/get.dart'; Widget content( - ThemeData theme, - bool isSave, - BuildContext context, - DynamicItemModel item, - bool isDetail, - Function(List, int)? callback, { - floor = 1, + BuildContext context, { + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isSave, + required bool isDetail, required double maxWidth, + Function(List, int)? callback, }) { if (floor == 1) { maxWidth -= 24; } - TextSpan? richNodes = richNode(theme, item, context, maxWidth: maxWidth); + TextSpan? richNodes = richNode( + context, + theme: theme, + item: item, + maxWidth: maxWidth, + ); + final moduleDynamic = item.modules.moduleDynamic; + final pics = moduleDynamic?.major?.opus?.pics; return Padding( padding: floor == 1 ? const EdgeInsets.fromLTRB(12, 0, 12, 6) @@ -28,13 +35,13 @@ Widget content( child: Column( crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (item.modules.moduleDynamic?.topic != null) + if (moduleDynamic?.topic case final topic?) GestureDetector( onTap: () => Get.toNamed( '/dynTopic', parameters: { - 'id': item.modules.moduleDynamic!.topic!.id!.toString(), - 'name': item.modules.moduleDynamic!.topic!.name!, + 'id': topic.id!.toString(), + 'name': topic.name!, }, ), child: Text.rich( @@ -51,7 +58,7 @@ Widget content( ), ), ), - TextSpan(text: item.modules.moduleDynamic!.topic!.name), + TextSpan(text: topic.name), ], ), style: TextStyle( @@ -79,10 +86,10 @@ Widget content( richNodes, maxLines: isSave ? null : 6, ), - if (item.modules.moduleDynamic?.major?.opus?.pics?.isNotEmpty == true) + if (pics?.isNotEmpty == true) CustomGridView( maxWidth: maxWidth, - picArr: item.modules.moduleDynamic!.major!.opus!.pics! + picArr: pics! .map( (item) => ImageModel( width: item.width, diff --git a/lib/pages/dynamics/widgets/dyn_content.dart b/lib/pages/dynamics/widgets/dyn_content.dart new file mode 100644 index 000000000..40fb7fd65 --- /dev/null +++ b/lib/pages/dynamics/widgets/dyn_content.dart @@ -0,0 +1,52 @@ +import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/additional_panel.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/blocked_item.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/content_panel.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/module_panel.dart'; +import 'package:flutter/material.dart'; + +List dynContent( + BuildContext context, { + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isSave, + required bool isDetail, + required double maxWidth, + Function(List, int)? callback, +}) { + final moduleDynamic = item.modules.moduleDynamic; + return [ + if (item.type != 'DYNAMIC_TYPE_NONE') + content( + context, + theme: theme, + isSave: isSave, + isDetail: isDetail, + item: item, + floor: floor, + callback: callback, + maxWidth: maxWidth, + ), + module( + context, + theme: theme, + isSave: isSave, + isDetail: isDetail, + item: item, + floor: floor, + callback: callback, + maxWidth: maxWidth, + ), + if (moduleDynamic?.additional case final additional?) + addWidget( + theme: theme, + context, + idStr: item.idStr, + additional: additional, + floor: floor, + ), + if (moduleDynamic?.major?.blocked case final blocked?) + blockedItem(theme: theme, blocked: blocked, maxWidth: maxWidth), + ]; +} diff --git a/lib/pages/dynamics/widgets/dynamic_panel.dart b/lib/pages/dynamics/widgets/dynamic_panel.dart index 5fab2bddf..9afe5fd77 100644 --- a/lib/pages/dynamics/widgets/dynamic_panel.dart +++ b/lib/pages/dynamics/widgets/dynamic_panel.dart @@ -2,11 +2,8 @@ import 'package:PiliPlus/common/widgets/dyn/ink_well.dart'; import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; import 'package:PiliPlus/pages/dynamics/widgets/action_panel.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/additional_panel.dart'; import 'package:PiliPlus/pages/dynamics/widgets/author_panel.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/blocked_item.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/content_panel.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/module_panel.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/dyn_content.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart' hide InkWell; @@ -76,37 +73,20 @@ class DynamicPanel extends StatelessWidget { padding: const EdgeInsets.fromLTRB(12, 12, 12, 6), child: authorWidget, ), - if (item.type != 'DYNAMIC_TYPE_NONE') - content( - theme, - isSave, - context, - item, - isDetail, - callback, - maxWidth: maxWidth, - ), - module( - theme, - isSave, - item, + ...dynContent( context, - isDetail, - callback, + theme: theme, + isSave: isSave, + isDetail: isDetail, + item: item, + floor: 1, + callback: callback, maxWidth: maxWidth, ), - if (item.modules.moduleDynamic?.additional != null) - addWidget(theme, item, context), - if (item.modules.moduleDynamic?.major?.blocked != null) - blockedItem( - theme, - item.modules.moduleDynamic!.major!.blocked!, - maxWidth: maxWidth, - ), const SizedBox(height: 2), if (!isDetail) ...[ ActionPanel(item: item), - if (item.modules.moduleFold case ModuleFold moduleFold) ...[ + if (item.modules.moduleFold case final moduleFold?) ...[ Divider( height: 1, color: theme.dividerColor.withValues(alpha: 0.1), diff --git a/lib/pages/dynamics/widgets/forward_panel.dart b/lib/pages/dynamics/widgets/forward_panel.dart new file mode 100644 index 000000000..e83bdad43 --- /dev/null +++ b/lib/pages/dynamics/widgets/forward_panel.dart @@ -0,0 +1,135 @@ +import 'package:PiliPlus/common/widgets/dyn/ink_well.dart'; +import 'package:PiliPlus/common/widgets/image/image_save.dart'; +import 'package:PiliPlus/models/dynamics/result.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/dyn_content.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/module_panel.dart'; +import 'package:PiliPlus/utils/date_util.dart'; +import 'package:PiliPlus/utils/page_utils.dart'; +import 'package:flutter/material.dart' hide InkWell; +import 'package:get/get.dart'; + +Widget forwardPanel( + BuildContext context, { + required int floor, + required ThemeData theme, + required DynamicItemModel orig, + required bool isSave, + required bool isDetail, + required double maxWidth, + Function(List, int)? callback, +}) { + final moduleDynamic = orig.modules.moduleDynamic; + final major = moduleDynamic?.major; + final isNoneMajor = major?.type == 'MAJOR_TYPE_NONE'; + + Widget child; + + if (isNoneMajor) { + child = noneWidget(theme, major?.none?.tips); + } else { + child = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + _forwardAuthor( + theme: theme, + moduleAuthor: orig.modules.moduleAuthor!, + isSave: isSave, + ), + const SizedBox(height: 5), + ...dynContent( + context, + theme: theme, + isSave: isSave, + isDetail: isDetail, + item: orig, + floor: floor + 1, + callback: callback, + maxWidth: maxWidth - 30, + ), + ], + ); + } + + child = Container( + padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), + color: theme.dividerColor.withValues(alpha: 0.08), + child: child, + ); + + if (isNoneMajor) { + return child; + } + + return InkWell( + onTap: () => PageUtils.pushDynDetail(orig), + onLongPress: () { + String? title, cover, bvid; + switch (orig.type) { + case 'DYNAMIC_TYPE_AV': + title = major?.archive?.title; + cover = major?.archive?.cover; + bvid = major?.archive?.bvid; + break; + case 'DYNAMIC_TYPE_UGC_SEASON': + title = major?.ugcSeason?.title; + cover = major?.ugcSeason?.cover; + bvid = major?.ugcSeason?.bvid; + break; + case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': + title = major?.pgc?.title; + cover = major?.pgc?.cover; + break; + case 'DYNAMIC_TYPE_LIVE_RCMD': + title = major?.liveRcmd?.title; + cover = major?.liveRcmd?.cover; + break; + case 'DYNAMIC_TYPE_LIVE': + title = major?.live?.title; + cover = major?.live?.cover; + break; + default: + return; + } + if (cover != null) { + imageSaveDialog( + title: title, + cover: cover, + bvid: bvid, + ); + } + }, + child: child, + ); +} + +Widget _forwardAuthor({ + required ThemeData theme, + required ModuleAuthorModel moduleAuthor, + required bool isSave, +}) { + final isNormalAuth = moduleAuthor.type == 'AUTHOR_TYPE_NORMAL'; + return Row( + children: [ + GestureDetector( + onTap: isNormalAuth + ? () => Get.toNamed('/member?mid=${moduleAuthor.mid}') + : null, + child: Text( + '${isNormalAuth ? '@' : ''}${moduleAuthor.name}', + style: TextStyle(color: theme.colorScheme.primary), + ), + ), + const SizedBox(width: 6), + Text( + isSave + ? DateUtil.format(moduleAuthor.pubTs, format: DateUtil.longFormatDs) + : DateUtil.dateFormat(moduleAuthor.pubTs), + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: theme.textTheme.labelSmall!.fontSize, + ), + ), + ], + ); +} diff --git a/lib/pages/dynamics/widgets/live_panel.dart b/lib/pages/dynamics/widgets/live_panel.dart index b76866360..902859e24 100644 --- a/lib/pages/dynamics/widgets/live_panel.dart +++ b/lib/pages/dynamics/widgets/live_panel.dart @@ -1,73 +1,65 @@ -import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; Widget livePanel( - ThemeData theme, - bool isDetail, - DynamicItemModel item, BuildContext context, { - int floor = 1, + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isDetail, + required double maxWidth, + Function(List, int)? callback, }) { - DynamicMajorModel? content = item.modules.moduleDynamic!.major; - if (content == null) { + DynamicLive2Model? live = item.modules.moduleDynamic!.major!.live; + if (live == null) { return const SizedBox.shrink(); } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () => PageUtils.toLiveRoom(content.live?.id), - onLongPress: () { - Feedback.forLongPress(context); - imageSaveDialog( - title: content.live!.title, - cover: content.live!.cover, - ); - }, - child: Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - NetworkImgLayer( - width: 120, - height: 75, - src: content.live!.cover, - ), - const SizedBox(width: 10), - Expanded( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Text( - content.live!.title!, - maxLines: isDetail ? null : 2, - overflow: isDetail ? null : TextOverflow.ellipsis, - ), - const SizedBox(height: 4), - if (content.live?.descFirst != null) - Text( - content.live!.descFirst!, - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: theme.textTheme.labelMedium!.fontSize, - ), - ), - ], - ), - ), - if (content.live!.badge?.text != null) - Text( - content.live!.badge!.text!, - style: TextStyle( - fontSize: theme.textTheme.labelMedium!.fontSize, - ), - ), - ], + return Padding( + padding: floor == 1 + ? const EdgeInsets.symmetric(horizontal: 12) + : EdgeInsets.zero, + child: Row( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + NetworkImgLayer( + width: 120, + height: 75, + src: live.cover, ), - ), - ], + const SizedBox(width: 10), + Expanded( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Text( + live.title!, + maxLines: isDetail ? null : 2, + overflow: isDetail ? null : TextOverflow.ellipsis, + ), + const SizedBox(height: 4), + if (live.descFirst case final descFirst?) + Text( + descFirst, + style: TextStyle( + color: theme.colorScheme.outline, + fontSize: theme.textTheme.labelMedium!.fontSize, + ), + ), + ], + ), + ), + if (live.badge?.text case final badge?) + Text( + badge, + style: TextStyle( + fontSize: theme.textTheme.labelMedium!.fontSize, + color: live.liveState == 1 + ? theme.colorScheme.primary + : theme.colorScheme.outline, + ), + ), + ], + ), ); } diff --git a/lib/pages/dynamics/widgets/live_panel_sub.dart b/lib/pages/dynamics/widgets/live_panel_sub.dart index d90ac844a..8d2243779 100644 --- a/lib/pages/dynamics/widgets/live_panel_sub.dart +++ b/lib/pages/dynamics/widgets/live_panel_sub.dart @@ -3,117 +3,116 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; Widget livePanelSub( - ThemeData theme, - bool isDetail, - DynamicItemModel item, BuildContext context, { - int floor = 1, + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isDetail, required double maxWidth, + Function(List, int)? callback, }) { - maxWidth -= 24; - SubscriptionNew? subItem = item.modules.moduleDynamic!.major?.subscriptionNew; - LivePlayInfo? content = subItem?.liveRcmd?.content?.livePlayInfo; - if (subItem == null || content == null) { + LivePlayInfo? live = item + .modules + .moduleDynamic! + .major + ?.subscriptionNew + ?.liveRcmd + ?.content + ?.livePlayInfo; + if (live == null) { return const SizedBox.shrink(); } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), - child: GestureDetector( - onTap: () => PageUtils.toLiveRoom(content.roomId), - child: Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - width: maxWidth, - height: maxWidth / StyleString.aspectRatio, - src: content.cover, - quality: 40, - ), - PBadge( - text: content.watchedShow?.textLarge, + EdgeInsets padding; + if (floor == 1) { + maxWidth -= 24; + padding = const EdgeInsets.symmetric(horizontal: 12); + } else { + padding = EdgeInsets.zero; + } + return Padding( + padding: padding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + width: maxWidth, + height: maxWidth / StyleString.aspectRatio, + src: live.cover, + quality: 40, + ), + PBadge( + text: live.watchedShow?.textLarge, + top: 6, + right: 65, + fontSize: 10.5, + type: PBadgeType.gray, + ), + if (live.liveStatus == 1) + Positioned( + right: 6, top: 6, - right: 65, - fontSize: 10.5, - type: PBadgeType.gray, + child: Image.asset( + height: 16, + 'assets/images/live/live.gif', + filterQuality: FilterQuality.low, + ), + ) + else + const PBadge( + text: '直播结束', + top: 6, + right: 6, ), - if (content.liveStatus == 1) - Positioned( - right: 6, - top: 6, - child: Image.asset( - height: 16, - 'assets/images/live/live.gif', - filterQuality: FilterQuality.low, - ), - ) - else - const PBadge( - text: '直播结束', - top: 6, - right: 6, - ), - if (content.areaName != null) - Positioned( - left: 0, - right: 0, - bottom: 0, - child: Container( - height: 80, - alignment: Alignment.bottomLeft, - padding: const EdgeInsets.fromLTRB(12, 0, 10, 10), - decoration: BoxDecoration( - gradient: const LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.transparent, - Colors.black45, - ], - ), - borderRadius: floor == 1 - ? const BorderRadius.only( - bottomLeft: StyleString.imgRadius, - bottomRight: StyleString.imgRadius, - ) - : const BorderRadius.only( - bottomLeft: Radius.circular(6), - bottomRight: Radius.circular(6), - ), + if (live.areaName case final areaName?) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + height: 80, + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.fromLTRB(12, 0, 10, 10), + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.transparent, + Colors.black45, + ], ), - child: Text( - content.areaName!, - style: TextStyle( - fontSize: theme.textTheme.labelMedium!.fontSize, - color: Colors.white, - ), + borderRadius: BorderRadius.only( + bottomLeft: StyleString.imgRadius, + bottomRight: StyleString.imgRadius, + ), + ), + child: Text( + areaName, + style: TextStyle( + fontSize: theme.textTheme.labelMedium!.fontSize, + color: Colors.white, ), ), ), - ], - ), + ), + ], ), - ), - const SizedBox(height: 6), - if (content.title != null) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, - ), - child: Text( - content.title!, + const SizedBox(height: 6), + if (live.title case final title?) + Text( + title, maxLines: isDetail ? null : 1, style: const TextStyle(fontWeight: FontWeight.bold), overflow: isDetail ? null : TextOverflow.ellipsis, ), - ), - const SizedBox(height: 2), - ], + const SizedBox(height: 2), + ], + ), ); } diff --git a/lib/pages/dynamics/widgets/live_rcmd_panel.dart b/lib/pages/dynamics/widgets/live_rcmd_panel.dart index ed77b8e1f..280f9eaa9 100644 --- a/lib/pages/dynamics/widgets/live_rcmd_panel.dart +++ b/lib/pages/dynamics/widgets/live_rcmd_panel.dart @@ -3,117 +3,110 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/utils/page_utils.dart'; import 'package:flutter/material.dart'; Widget liveRcmdPanel( - ThemeData theme, - bool isDetail, - DynamicItemModel item, BuildContext context, { - int floor = 1, + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isDetail, required double maxWidth, + Function(List, int)? callback, }) { - maxWidth -= 24; DynamicLiveModel? liveRcmd = item.modules.moduleDynamic?.major?.liveRcmd; if (liveRcmd == null) { return const SizedBox.shrink(); } - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.symmetric(horizontal: StyleString.safeSpace), - child: GestureDetector( - onTap: () => PageUtils.pushDynDetail(item), - child: Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - width: maxWidth, - height: maxWidth / StyleString.aspectRatio, - src: liveRcmd.cover, - quality: 40, - ), - PBadge( - text: liveRcmd.watchedShow?.textLarge, + EdgeInsets padding; + if (floor == 1) { + maxWidth -= 24; + padding = const EdgeInsets.symmetric(horizontal: 12); + } else { + padding = EdgeInsets.zero; + } + return Padding( + padding: padding, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + width: maxWidth, + height: maxWidth / StyleString.aspectRatio, + src: liveRcmd.cover, + quality: 40, + ), + PBadge( + text: liveRcmd.watchedShow?.textLarge, + top: 6, + right: 65, + fontSize: 10.5, + type: PBadgeType.gray, + ), + if (liveRcmd.liveStatus == 1) + Positioned( + right: 6, top: 6, - right: 65, - fontSize: 10.5, + child: Image.asset( + height: 16, + 'assets/images/live/live.gif', + filterQuality: FilterQuality.low, + ), + ) + else + const PBadge( + text: '直播结束', + top: 6, + right: 6, type: PBadgeType.gray, ), - if (liveRcmd.liveStatus == 1) - Positioned( - right: 6, - top: 6, - child: Image.asset( - height: 16, - 'assets/images/live/live.gif', - filterQuality: FilterQuality.low, - ), - ) - else - const PBadge( - text: '直播结束', - top: 6, - right: 6, - type: PBadgeType.gray, - ), - if (liveRcmd.areaName != null) - Positioned( - left: 0, - right: 0, - bottom: 0, - child: Container( - height: 80, - alignment: Alignment.bottomLeft, - padding: const EdgeInsets.fromLTRB(12, 0, 10, 10), - decoration: BoxDecoration( - gradient: const LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.transparent, - Colors.black45, - ], - ), - borderRadius: floor == 1 - ? const BorderRadius.only( - bottomLeft: StyleString.imgRadius, - bottomRight: StyleString.imgRadius, - ) - : const BorderRadius.only( - bottomLeft: Radius.circular(6), - bottomRight: Radius.circular(6), - ), + if (liveRcmd.areaName case final areaName?) + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + height: 80, + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.fromLTRB(12, 0, 10, 10), + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.transparent, + Colors.black45, + ], ), - child: Text( - liveRcmd.areaName!, - style: TextStyle( - fontSize: theme.textTheme.labelMedium!.fontSize, - color: Colors.white, - ), + borderRadius: BorderRadius.only( + bottomLeft: StyleString.imgRadius, + bottomRight: StyleString.imgRadius, + ), + ), + child: Text( + areaName, + style: TextStyle( + fontSize: theme.textTheme.labelMedium!.fontSize, + color: Colors.white, ), ), ), - ], - ), + ), + ], ), - ), - const SizedBox(height: 6), - if (liveRcmd.title != null) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, - ), - child: Text( - liveRcmd.title!, + const SizedBox(height: 6), + if (liveRcmd.title case final title?) + Text( + title, maxLines: isDetail ? null : 1, style: const TextStyle(fontWeight: FontWeight.bold), overflow: isDetail ? null : TextOverflow.ellipsis, ), - ), - const SizedBox(height: 2), - ], + const SizedBox(height: 2), + ], + ), ); } diff --git a/lib/pages/dynamics/widgets/module_panel.dart b/lib/pages/dynamics/widgets/module_panel.dart index b9bb13ec9..c92dd8591 100644 --- a/lib/pages/dynamics/widgets/module_panel.dart +++ b/lib/pages/dynamics/widgets/module_panel.dart @@ -1,36 +1,60 @@ -// 转发 import 'package:PiliPlus/common/constants.dart'; import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/dyn/ink_well.dart'; -import 'package:PiliPlus/common/widgets/image/image_save.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/dynamics/result.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/additional_panel.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/blocked_item.dart'; -import 'package:PiliPlus/pages/dynamics/widgets/content_panel.dart'; +import 'package:PiliPlus/pages/dynamics/widgets/forward_panel.dart'; import 'package:PiliPlus/pages/dynamics/widgets/live_panel.dart'; import 'package:PiliPlus/pages/dynamics/widgets/live_panel_sub.dart'; import 'package:PiliPlus/pages/dynamics/widgets/live_rcmd_panel.dart'; import 'package:PiliPlus/pages/dynamics/widgets/video_panel.dart'; -import 'package:PiliPlus/utils/date_util.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:flutter/material.dart' hide InkWell; import 'package:font_awesome_flutter/font_awesome_flutter.dart'; -import 'package:get/get.dart'; + +Widget noneWidget(ThemeData theme, String? tips) => Row( + spacing: 5, + children: [ + Icon( + Icons.error, + size: 18, + color: theme.colorScheme.outline, + ), + Text( + tips ?? '已失效', + style: TextStyle(color: theme.colorScheme.outline), + ), + ], +); Widget module( - ThemeData theme, - bool isSave, - DynamicItemModel item, - BuildContext context, - bool isDetail, - Function(List, int)? callback, { - floor = 1, + BuildContext context, { + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isSave, + required bool isDetail, required double maxWidth, + Function(List, int)? callback, }) { + final moduleDynamic = item.modules.moduleDynamic; + final major = moduleDynamic?.major; + + if (major?.type == 'MAJOR_TYPE_NONE') { + return noneWidget(theme, major?.none?.tips); + } + switch (item.type) { + case 'DYNAMIC_TYPE_NONE': + return Row( + spacing: 4, + children: [ + const Icon(FontAwesomeIcons.ghost, size: 14), + Text(major!.none!.tips!), + ], + ); // 图文 case 'DYNAMIC_TYPE_DRAW': // 文章 @@ -44,173 +68,46 @@ Widget module( case 'DYNAMIC_TYPE_PGC_UNION': case 'DYNAMIC_TYPE_COURSES_SEASON': return videoSeasonWidget( - theme, - isSave, - isDetail, - item, context, - callback, + theme: theme, + item: item, floor: floor, + isSave: isSave, + isDetail: isDetail, + callback: callback, maxWidth: maxWidth, ); // 转发 case 'DYNAMIC_TYPE_FORWARD': - final orig = item.orig!; - final isNoneMajor = - orig.modules.moduleDynamic?.major?.type == 'MAJOR_TYPE_NONE'; - late final isNormalAuth = - orig.modules.moduleAuthor!.type == 'AUTHOR_TYPE_NORMAL'; - if (isNoneMajor) { - if (orig.modules.moduleDynamic?.major?.none?.tips?.isNotEmpty == true) { - return Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), - color: theme.dividerColor.withValues(alpha: 0.08), - child: Row( - children: [ - Icon( - Icons.error, - size: 18, - color: theme.colorScheme.outline, - ), - const SizedBox(width: 5), - Text( - orig.modules.moduleDynamic!.major!.none!.tips!, - style: TextStyle(color: theme.colorScheme.outline), - ), - ], - ), - ); - } else { - return const SizedBox.shrink(); - } - } - maxWidth -= 30; - return InkWell( - onTap: () => PageUtils.pushDynDetail(orig), - onLongPress: () { - String? title, cover, bvid; - late var origMajor = orig.modules.moduleDynamic?.major; - late var major = item.modules.moduleDynamic?.major; - switch (orig.type) { - case 'DYNAMIC_TYPE_AV': - title = origMajor?.archive?.title; - cover = origMajor?.archive?.cover; - bvid = origMajor?.archive?.bvid; - break; - case 'DYNAMIC_TYPE_UGC_SEASON': - title = origMajor?.ugcSeason?.title; - cover = origMajor?.ugcSeason?.cover; - bvid = origMajor?.ugcSeason?.bvid; - break; - case 'DYNAMIC_TYPE_PGC' || 'DYNAMIC_TYPE_PGC_UNION': - title = origMajor?.pgc?.title; - cover = origMajor?.pgc?.cover; - break; - case 'DYNAMIC_TYPE_LIVE_RCMD': - title = major?.liveRcmd?.title; - cover = major?.liveRcmd?.cover; - break; - case 'DYNAMIC_TYPE_LIVE': - title = major?.live?.title; - cover = major?.live?.cover; - break; - default: - return; - } - imageSaveDialog( - title: title, - cover: cover, - bvid: bvid, - ); - }, - child: Container( - padding: const EdgeInsets.symmetric(horizontal: 15, vertical: 8), - color: theme.dividerColor.withValues(alpha: 0.08), - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - GestureDetector( - onTap: isNormalAuth - ? () => Get.toNamed( - '/member?mid=${orig.modules.moduleAuthor!.mid}', - ) - : null, - child: Text( - '${isNormalAuth ? '@' : ''}${orig.modules.moduleAuthor!.name}', - style: TextStyle(color: theme.colorScheme.primary), - ), - ), - const SizedBox(width: 6), - Text( - isSave - ? DateUtil.format( - orig.modules.moduleAuthor!.pubTs, - format: DateUtil.longFormatDs, - ) - : DateUtil.dateFormat(orig.modules.moduleAuthor!.pubTs), - style: TextStyle( - color: theme.colorScheme.outline, - fontSize: theme.textTheme.labelSmall!.fontSize, - ), - ), - ], - ), - const SizedBox(height: 5), - content( - theme, - isSave, - context, - orig, - isDetail, - callback, - floor: floor + 1, - maxWidth: maxWidth, - ), - module( - theme, - isSave, - orig, - context, - isDetail, - callback, - floor: floor + 1, - maxWidth: maxWidth, - ), - if (orig.modules.moduleDynamic?.additional != null) - addWidget(theme, orig, context, floor: floor + 1), - if (orig.modules.moduleDynamic?.major?.blocked != null) - blockedItem( - theme, - orig.modules.moduleDynamic!.major!.blocked!, - maxWidth: maxWidth, - ), - ], - ), - ), + return forwardPanel( + context, + theme: theme, + isSave: isSave, + orig: item.orig!, + isDetail: isDetail, + callback: callback, + floor: floor + 1, + maxWidth: maxWidth, ); // 直播 case 'DYNAMIC_TYPE_LIVE_RCMD': return liveRcmdPanel( - theme, - isDetail, - item, context, + theme: theme, + isDetail: isDetail, + item: item, floor: floor, maxWidth: maxWidth, ); // 直播 case 'DYNAMIC_TYPE_LIVE': - return livePanel(theme, isDetail, item, context, floor: floor); - case 'DYNAMIC_TYPE_NONE': - return Row( - spacing: 4, - children: [ - const Icon(FontAwesomeIcons.ghost, size: 14), - Text(item.modules.moduleDynamic!.major!.none!.tips!), - ], + return livePanel( + context, + theme: theme, + item: item, + floor: floor, + isDetail: isDetail, + maxWidth: maxWidth, ); // 活动 case 'DYNAMIC_TYPE_COMMON_SQUARE': @@ -225,7 +122,7 @@ Widget module( borderRadius: floor == 1 ? null : StyleString.mdRadius, onTap: () { try { - String url = item.modules.moduleDynamic!.major!.common!.jumpUrl!; + String url = major.common!.jumpUrl!; if (url.contains('bangumi/play') && PageUtils.viewPgcFromUri(url)) { return; @@ -272,7 +169,7 @@ Widget module( crossAxisAlignment: CrossAxisAlignment.start, children: [ Text( - item.modules.moduleDynamic!.major!.common!.title!, + major!.common!.title!, style: TextStyle(color: theme.colorScheme.primary), maxLines: 1, overflow: TextOverflow.ellipsis, @@ -286,7 +183,7 @@ Widget module( ?.isNotEmpty == true) Text( - item.modules.moduleDynamic!.major!.common!.desc!, + major.common!.desc!, style: TextStyle( color: theme.colorScheme.outline, fontSize: theme.textTheme.labelMedium!.fontSize, @@ -303,7 +200,7 @@ Widget module( ), ); case 'DYNAMIC_TYPE_MUSIC': - final Map music = item.modules.moduleDynamic!.major!.music!; + final Map music = major!.music!; return InkWell( onTap: () => PageUtils.handleWebview("https:${music['jump_url']}"), child: Container( @@ -355,24 +252,22 @@ Widget module( crossAxisAlignment: CrossAxisAlignment.start, children: [ if (floor == 1) const SizedBox(width: 12), - if (item.modules.moduleDynamic!.major!.medialist!.cover?.isNotEmpty == - true) ...[ + if (major?.medialist?.cover?.isNotEmpty == true) ...[ Stack( clipBehavior: Clip.none, children: [ Hero( - tag: item.modules.moduleDynamic!.major!.medialist!.cover!, + tag: major!.medialist!.cover!, child: NetworkImgLayer( width: 180, height: 110, - src: item.modules.moduleDynamic!.major!.medialist!.cover, + src: major.medialist!.cover, ), ), PBadge( right: 6, top: 6, - text: - item.modules.moduleDynamic!.major!.medialist!.badge?.text, + text: major.medialist!.badge?.text, ), ], ), @@ -387,17 +282,16 @@ Widget module( children: [ const SizedBox(height: 4), Text( - item.modules.moduleDynamic!.major!.medialist!.title!, + major!.medialist!.title!, style: TextStyle( fontSize: theme.textTheme.titleMedium!.fontSize, fontWeight: FontWeight.bold, ), ), - if (item.modules.moduleDynamic?.major?.medialist?.subTitle != - null) ...[ + if (major.medialist?.subTitle != null) ...[ const Spacer(), Text( - item.modules.moduleDynamic!.major!.medialist!.subTitle!, + major.medialist!.subTitle!, style: TextStyle( fontSize: theme.textTheme.labelLarge!.fontSize, color: theme.colorScheme.outline, @@ -413,14 +307,14 @@ Widget module( ); case 'DYNAMIC_TYPE_SUBSCRIPTION_NEW' - when item.modules.moduleDynamic?.major?.type == - 'MAJOR_TYPE_SUBSCRIPTION_NEW': + when major?.type == 'MAJOR_TYPE_SUBSCRIPTION_NEW': return livePanelSub( - theme, - isDetail, - item, context, + theme: theme, + isDetail: isDetail, + item: item, floor: floor, + callback: callback, maxWidth: maxWidth, ); diff --git a/lib/pages/dynamics/widgets/rich_node_panel.dart b/lib/pages/dynamics/widgets/rich_node_panel.dart index 505d6f927..d05a3e18d 100644 --- a/lib/pages/dynamics/widgets/rich_node_panel.dart +++ b/lib/pages/dynamics/widgets/rich_node_panel.dart @@ -19,31 +19,32 @@ import 'package:get/get.dart'; // 富文本 TextSpan? richNode( - ThemeData theme, - DynamicItemModel item, BuildContext context, { + required ThemeData theme, + required DynamicItemModel item, required double maxWidth, }) { try { late final style = TextStyle(color: theme.colorScheme.primary); List spanChildren = []; + final moduleDynamic = item.modules.moduleDynamic; List? richTextNodes; - if (item.modules.moduleDynamic?.desc != null) { - richTextNodes = item.modules.moduleDynamic!.desc!.richTextNodes; - } else if (item.modules.moduleDynamic?.major != null) { + if (moduleDynamic?.desc case final desc?) { + richTextNodes = desc.richTextNodes; + } else if (moduleDynamic?.major?.opus case final opus?) { // 动态页面 richTextNodes 层级可能与主页动态层级不同 - richTextNodes = - item.modules.moduleDynamic!.major!.opus?.summary?.richTextNodes; - if (item.modules.moduleDynamic?.major?.opus?.title != null) { + richTextNodes = opus.summary?.richTextNodes; + if (opus.title case final title?) { spanChildren.add( TextSpan( - text: '${item.modules.moduleDynamic!.major!.opus!.title!}\n', + text: '$title\n', style: const TextStyle(fontWeight: FontWeight.bold), ), ); } } + if (richTextNodes == null || richTextNodes.isEmpty) { return null; } else { diff --git a/lib/pages/dynamics/widgets/up_panel.dart b/lib/pages/dynamics/widgets/up_panel.dart index c1bb9876e..3e7a3f018 100644 --- a/lib/pages/dynamics/widgets/up_panel.dart +++ b/lib/pages/dynamics/widgets/up_panel.dart @@ -1,3 +1,4 @@ +import 'package:PiliPlus/common/widgets/dyn/ink_well.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/dynamic/up_panel_position.dart'; import 'package:PiliPlus/models/common/image_type.dart'; @@ -6,7 +7,7 @@ import 'package:PiliPlus/pages/dynamics/controller.dart'; import 'package:PiliPlus/pages/live_follow/view.dart'; import 'package:PiliPlus/utils/feed_back.dart'; import 'package:PiliPlus/utils/page_utils.dart'; -import 'package:flutter/material.dart'; +import 'package:flutter/material.dart' hide InkWell; import 'package:get/get.dart'; class UpPanel extends StatefulWidget { diff --git a/lib/pages/dynamics/widgets/video_panel.dart b/lib/pages/dynamics/widgets/video_panel.dart index 5cbf93588..a2dc78080 100644 --- a/lib/pages/dynamics/widgets/video_panel.dart +++ b/lib/pages/dynamics/widgets/video_panel.dart @@ -8,43 +8,20 @@ import 'package:PiliPlus/utils/num_util.dart'; import 'package:flutter/material.dart'; Widget videoSeasonWidget( - ThemeData theme, - bool isSave, - bool isDetail, - DynamicItemModel item, - BuildContext context, - Function(List, int)? callback, { - floor = 1, + BuildContext context, { + required int floor, + required ThemeData theme, + required DynamicItemModel item, + required bool isSave, + required bool isDetail, required double maxWidth, + Function(List, int)? callback, }) { - if (item.modules.moduleDynamic?.major?.type == 'MAJOR_TYPE_NONE') { - return item.modules.moduleDynamic?.major?.none?.tips != null - ? Row( - children: [ - Icon( - Icons.error, - size: 18, - color: theme.colorScheme.outline, - ), - const SizedBox(width: 5), - Text( - item.modules.moduleDynamic!.major!.none!.tips!, - style: TextStyle(color: theme.colorScheme.outline), - ), - ], - ) - : const SizedBox.shrink(); - } - // type archive ugcSeason // archive 视频/显示发布人 // ugcSeason 合集/不显示发布人 - // floor 1 2 - // 1 投稿视频 铺满 borderRadius 0 - // 2 转发视频 铺满 borderRadius 6 - - DynamicArchiveModel? itemContent = switch (item.type) { + DynamicArchiveModel? video = switch (item.type) { 'DYNAMIC_TYPE_AV' => item.modules.moduleDynamic?.major?.archive, 'DYNAMIC_TYPE_UGC_SEASON' => item.modules.moduleDynamic?.major?.ugcSeason, 'DYNAMIC_TYPE_PGC' || @@ -53,121 +30,117 @@ Widget videoSeasonWidget( _ => null, }; - if (itemContent == null) { + if (video == null) { return const SizedBox.shrink(); } - Widget buildCover() { - if (floor == 1) { - maxWidth -= 24; - } - return Stack( - clipBehavior: Clip.none, - children: [ - NetworkImgLayer( - width: maxWidth, - height: maxWidth / StyleString.aspectRatio, - src: itemContent.cover, - quality: 40, - ), - if (itemContent.badge?.text != null) - PBadge( - text: itemContent.badge!.text, - top: 8.0, - right: 10.0, - bottom: null, - left: null, - type: switch (itemContent.badge!.text) { - '充电专属' => PBadgeType.error, - _ => PBadgeType.primary, - }, - ), - Positioned( - left: 0, - right: 0, - bottom: 0, - child: Container( - height: 70, - alignment: Alignment.bottomLeft, - padding: const EdgeInsets.fromLTRB(10, 0, 8, 8), - decoration: const BoxDecoration( - gradient: LinearGradient( - begin: Alignment.topCenter, - end: Alignment.bottomCenter, - colors: [ - Colors.transparent, - Colors.black54, - ], - ), - borderRadius: BorderRadius.only( - bottomLeft: StyleString.imgRadius, - bottomRight: StyleString.imgRadius, - ), - ), - child: DefaultTextStyle.merge( - style: TextStyle( - fontSize: theme.textTheme.labelMedium!.fontSize, - color: Colors.white, - ), - child: Row( - crossAxisAlignment: CrossAxisAlignment.end, - children: [ - if (itemContent.durationText != null) ...[ - DecoratedBox( - decoration: const BoxDecoration( - color: Colors.black45, - borderRadius: BorderRadius.all(Radius.circular(4)), - ), - child: Text(' ${itemContent.durationText} '), - ), - const SizedBox(width: 6), - ], - if (itemContent.stat != null) ...[ - Text('${NumUtil.numFormat(itemContent.stat!.play)}次围观'), - const SizedBox(width: 6), - Text('${NumUtil.numFormat(itemContent.stat!.danmu)}条弹幕'), - ], - const Spacer(), - Image.asset( - 'assets/images/play.png', - width: 50, - height: 50, - ), - ], - ), - ), - ), - ), - ], - ); + EdgeInsets padding; + if (floor == 1) { + maxWidth -= 24; + padding = const EdgeInsets.symmetric(horizontal: 12); + } else { + padding = EdgeInsets.zero; } - - return Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - if (itemContent.cover != null) - if (floor == 1) - Padding( - padding: const EdgeInsets.symmetric( - horizontal: StyleString.safeSpace, - ), - child: buildCover(), - ) - else - buildCover(), - const SizedBox(height: 6), - if (itemContent.title != null) - Padding( - padding: floor == 1 - ? const EdgeInsets.only(left: 12, right: 12) - : EdgeInsets.zero, - child: Text( - itemContent.title!, + return Padding( + padding: padding, + child: Column( + spacing: 6, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (video.cover case final cover?) + Stack( + clipBehavior: Clip.none, + children: [ + NetworkImgLayer( + width: maxWidth, + height: maxWidth / StyleString.aspectRatio, + src: cover, + quality: 40, + ), + if (video.badge?.text case final badge?) + PBadge( + text: badge, + top: 8.0, + right: 10.0, + bottom: null, + left: null, + type: switch (badge) { + '充电专属' => PBadgeType.error, + _ => PBadgeType.primary, + }, + ), + Positioned( + left: 0, + right: 0, + bottom: 0, + child: Container( + height: 70, + alignment: Alignment.bottomLeft, + padding: const EdgeInsets.fromLTRB(10, 0, 8, 8), + decoration: const BoxDecoration( + gradient: LinearGradient( + begin: Alignment.topCenter, + end: Alignment.bottomCenter, + colors: [ + Colors.transparent, + Colors.black54, + ], + ), + borderRadius: BorderRadius.only( + bottomLeft: StyleString.imgRadius, + bottomRight: StyleString.imgRadius, + ), + ), + child: DefaultTextStyle.merge( + style: TextStyle( + fontSize: theme.textTheme.labelMedium!.fontSize, + color: Colors.white, + ), + child: Row( + crossAxisAlignment: CrossAxisAlignment.end, + children: [ + if (video.durationText case final durationText?) ...[ + DecoratedBox( + decoration: const BoxDecoration( + color: Colors.black45, + borderRadius: BorderRadius.all( + Radius.circular(4), + ), + ), + child: Text(' $durationText '), + ), + const SizedBox(width: 6), + ], + if (video.stat case final stat?) ...[ + Text( + '${NumUtil.numFormat(stat.play)}次围观', + ), + const SizedBox(width: 6), + Text( + '${NumUtil.numFormat(stat.danmu)}条弹幕', + ), + ], + const Spacer(), + Image.asset( + 'assets/images/play.png', + width: 50, + height: 50, + ), + ], + ), + ), + ), + ), + ], + ), + if (video.title case final title?) + Text( + title, maxLines: isDetail ? null : 1, style: const TextStyle(fontWeight: FontWeight.bold), overflow: isDetail ? null : TextOverflow.ellipsis, ), - ), - ], + ], + ), ); } diff --git a/lib/pages/dynamics_repost/view.dart b/lib/pages/dynamics_repost/view.dart index 2dda06e5c..e80eb67d5 100644 --- a/lib/pages/dynamics_repost/view.dart +++ b/lib/pages/dynamics_repost/view.dart @@ -50,21 +50,33 @@ class _RepostPanelState extends CommonRichTextPubPageState { late final _key = GlobalKey(); - late final _pic = - widget.pic ?? - widget.item?.modules.moduleDynamic?.major?.archive?.cover ?? - widget.item?.modules.moduleDynamic?.major?.pgc?.cover ?? - widget.item?.modules.moduleDynamic?.major?.opus?.pics?.firstOrNull?.url; + late final String? _pic; + late final String _text; + late final String? _uname; - late final _text = - widget.title ?? - widget.item?.modules.moduleDynamic?.major?.opus?.summary?.text ?? - widget.item?.modules.moduleDynamic?.desc?.text ?? - widget.item?.modules.moduleDynamic?.major?.archive?.title ?? - widget.item?.modules.moduleDynamic?.major?.pgc?.title ?? - ''; + @override + void initState() { + super.initState(); + late final modules = widget.item?.modules; + late final moduleDynamic = modules?.moduleDynamic; + late final major = moduleDynamic?.major; - late final _uname = widget.uname ?? widget.item?.modules.moduleAuthor?.name; + _pic = + widget.pic ?? + major?.archive?.cover ?? + major?.pgc?.cover ?? + major?.opus?.pics?.firstOrNull?.url; + + _text = + widget.title ?? + major?.opus?.summary?.text ?? + major?.archive?.title ?? + major?.pgc?.title ?? + moduleDynamic?.desc?.text ?? + ''; + + _uname = widget.uname ?? modules?.moduleAuthor?.name; + } @override void dispose() { diff --git a/lib/pages/member_shop/view.dart b/lib/pages/member_shop/view.dart index cdcc1274d..4fbf21462 100644 --- a/lib/pages/member_shop/view.dart +++ b/lib/pages/member_shop/view.dart @@ -105,11 +105,11 @@ class _MemberShopState extends State child: Center( child: FilledButton.tonal( onPressed: () { - if (_controller.clickUrl case String clickUrl) { + if (_controller.clickUrl case final clickUrl?) { final url = Uri.parse( clickUrl, ).queryParameters['url']; - if (url case String url) { + if (url case final url?) { Get.toNamed( '/webview', parameters: {'url': url}, diff --git a/lib/pages/member_shop/widgets/item.dart b/lib/pages/member_shop/widgets/item.dart index dceb775ad..1dbfa0597 100644 --- a/lib/pages/member_shop/widgets/item.dart +++ b/lib/pages/member_shop/widgets/item.dart @@ -2,7 +2,6 @@ import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/badge_type.dart'; import 'package:PiliPlus/models_new/space/space_shop/item.dart'; -import 'package:PiliPlus/models_new/space/space_shop/net_price.dart'; import 'package:PiliPlus/utils/extension.dart'; import 'package:flutter/material.dart'; import 'package:get/get.dart'; @@ -28,7 +27,7 @@ class MemberShopItem extends StatelessWidget { ), child: InkWell( onTap: () { - if (item.cardUrl case String cardUrl) { + if (item.cardUrl case final cardUrl?) { Get.toNamed('/webview', parameters: {'url': cardUrl}); } }, @@ -69,7 +68,7 @@ class MemberShopItem extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - if (item.netPrice case NetPrice netPrice) + if (item.netPrice case final netPrice?) Text.rich( style: TextStyle(color: colorScheme.vipColor), TextSpan( diff --git a/lib/utils/page_utils.dart b/lib/utils/page_utils.dart index 52ecf5738..520d22895 100644 --- a/lib/utils/page_utils.dart +++ b/lib/utils/page_utils.dart @@ -417,14 +417,14 @@ class PageUtils { // pgc if (archive.type == 2) { // jumpUrl - if (archive.jumpUrl case String jumpUrl) { + if (archive.jumpUrl case final jumpUrl?) { if (viewPgcFromUri(jumpUrl)) { return; } } // redirectUrl from intro final res = await VideoHttp.videoIntro(bvid: archive.bvid!); - if (res.dataOrNull?.redirectUrl case String redirectUrl) { + if (res.dataOrNull?.redirectUrl case final redirectUrl?) { if (viewPgcFromUri(redirectUrl)) { return; } @@ -434,7 +434,7 @@ class PageUtils { archive.jumpUrl.http2https, false, ) - case String redirectUrl) { + case final redirectUrl?) { if (viewPgcFromUri(redirectUrl)) { return; } @@ -479,6 +479,18 @@ class PageUtils { toLiveRoom(liveRcmd.roomId); break; + case 'DYNAMIC_TYPE_SUBSCRIPTION_NEW': + LivePlayInfo live = item + .modules + .moduleDynamic! + .major! + .subscriptionNew! + .liveRcmd! + .content! + .livePlayInfo!; + toLiveRoom(live.roomId); + break; + /// 合集查看 case 'DYNAMIC_TYPE_UGC_SEASON': DynamicArchiveModel ugcSeason = @@ -508,7 +520,7 @@ class PageUtils { case 'DYNAMIC_TYPE_MEDIALIST': if (item.modules.moduleDynamic?.major?.medialist - case Medialist medialist) { + case final medialist?) { final String? url = medialist.jumpUrl; if (url != null) { if (url.contains('medialist/detail/ml')) {