diff --git a/lib/models/dynamics/result.dart b/lib/models/dynamics/result.dart index f4cffc32..2b0ed1b1 100644 --- a/lib/models/dynamics/result.dart +++ b/lib/models/dynamics/result.dart @@ -97,6 +97,7 @@ class ItemModulesModel { // ModuleInterModel? moduleInter; // 专栏 + ModuleTop? moduleTop; List? moduleExtend; // opus的tag List? moduleContent; ModuleBlocked? moduleBlocked; @@ -122,6 +123,11 @@ class ItemModulesModel { ItemModulesModel.fromOpusJson(List> json) { for (var i in json) { switch (i['module_type']) { + case 'MODULE_TYPE_TOP': + moduleTop = i['module_top'] == null + ? null + : ModuleTop.fromJson(i['module_top']); + break; case 'MODULE_TYPE_TITLE': moduleTag = i['module_title'] == null ? null @@ -161,6 +167,37 @@ class ItemModulesModel { } } +class ModuleTop { + ModuleTopDisplay? display; + + ModuleTop.fromJson(Map json) { + display = json['display'] == null + ? null + : ModuleTopDisplay.fromJson(json['display']); + } +} + +class ModuleTopDisplay { + ModuleTopAlbum? album; + int? type; + + ModuleTopDisplay.fromJson(Map json) { + album = + json['album'] == null ? null : ModuleTopAlbum.fromJson(json['album']); + type = json['type']; + } +} + +class ModuleTopAlbum { + List? pics; + int? type; + + ModuleTopAlbum.fromJson(Map json) { + pics = (json['pics'] as List?)?.map((e) => Pic.fromJson(e)).toList(); + type = json['type']; + } +} + class ModuleBlocked { BgImg? bgImg; int? blockedType; diff --git a/lib/pages/article/controller.dart b/lib/pages/article/controller.dart index 52063512..01e41d61 100644 --- a/lib/pages/article/controller.dart +++ b/lib/pages/article/controller.dart @@ -28,6 +28,8 @@ class ArticleController extends ReplyController { RxBool showTitle = false.obs; + late final RxInt topIndex = 0.obs; + late final horizontalPreview = GStorage.horizontalPreview; late final showDynActionBar = GStorage.showDynActionBar; diff --git a/lib/pages/article/view.dart b/lib/pages/article/view.dart index 72b1a34d..65fd9604 100644 --- a/lib/pages/article/view.dart +++ b/lib/pages/article/view.dart @@ -1,12 +1,14 @@ import 'dart:math'; import 'package:PiliPlus/common/skeleton/video_reply.dart'; +import 'package:PiliPlus/common/widgets/badge.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/common/widgets/loading_widget/http_error.dart'; import 'package:PiliPlus/common/widgets/refresh_indicator.dart'; import 'package:PiliPlus/grpc/bilibili/main/community/reply/v1.pb.dart' show ReplyInfo; import 'package:PiliPlus/http/loading_state.dart'; +import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/common/reply/reply_sort_type.dart'; import 'package:PiliPlus/models/common/reply/reply_type.dart'; import 'package:PiliPlus/models/dynamics/result.dart' show DynamicStat; @@ -22,6 +24,7 @@ import 'package:PiliPlus/utils/grid.dart'; import 'package:PiliPlus/utils/page_utils.dart'; import 'package:PiliPlus/utils/storage.dart'; import 'package:PiliPlus/utils/utils.dart'; +import 'package:cached_network_image/cached_network_image.dart'; import 'package:easy_debounce/easy_throttle.dart'; import 'package:flutter/material.dart'; import 'package:flutter/rendering.dart'; @@ -390,6 +393,76 @@ class _ArticlePageState extends State _articleCtr.articleData?.publishTime; return SliverMainAxisGroup( slivers: [ + if (_articleCtr.type != 'read' && + _articleCtr.opusData?.modules.moduleTop?.display?.album + ?.pics?.isNotEmpty == + true) + SliverToBoxAdapter( + child: Builder( + builder: (context) { + final pics = _articleCtr.opusData!.modules.moduleTop! + .display!.album!.pics!; + final length = pics.length; + final first = pics.first; + double height; + double paddingRight; + if (first.height != null && first.width != null) { + final ratio = first.height! / first.width!; + height = min(maxWidth * ratio, Get.height * 0.55); + paddingRight = (maxWidth - height / ratio) / 2 + 12; + } else { + height = Get.height * 0.55; + paddingRight = 12; + } + return Stack( + clipBehavior: Clip.none, + children: [ + Container( + height: height, + width: maxWidth, + margin: const EdgeInsets.only(bottom: 10), + child: PageView.builder( + physics: const ClampingScrollPhysics(), + onPageChanged: (value) { + _articleCtr.topIndex.value = value; + }, + itemCount: length, + itemBuilder: (context, index) { + final url = pics[0].url!; + return GestureDetector( + onTap: () { + context.imageView( + imgList: pics + .map((e) => + SourceModel(url: e.url!)) + .toList(), + initialPage: index, + ); + }, + child: Hero( + tag: url, + child: CachedNetworkImage( + imageUrl: + Utils.thumbnailImgUrl(url, 60), + ), + ), + ); + }, + ), + ), + Obx( + () => PBadge( + top: 12, + right: paddingRight, + type: 'gray', + text: + '${_articleCtr.topIndex.value + 1}/$length'), + ), + ], + ); + }, + ), + ), if (_articleCtr.summary.title != null) SliverToBoxAdapter( child: Text( diff --git a/lib/pages/article/widgets/opus_content.dart b/lib/pages/article/widgets/opus_content.dart index 235720f1..1ff54225 100644 --- a/lib/pages/article/widgets/opus_content.dart +++ b/lib/pages/article/widgets/opus_content.dart @@ -1,6 +1,7 @@ import 'dart:math'; import 'package:PiliPlus/common/constants.dart'; +import 'package:PiliPlus/common/widgets/image/image_view.dart'; import 'package:PiliPlus/common/widgets/image/network_img_layer.dart'; import 'package:PiliPlus/models/common/image_preview_type.dart'; import 'package:PiliPlus/models/dynamics/article_content_model.dart' @@ -124,30 +125,39 @@ class OpusContent extends StatelessWidget { } return widget; case 2 when (element.pic != null): - element.pic!.pics!.first.onCalHeight(maxWidth); - return Hero( - tag: element.pic!.pics!.first.url!, - child: GestureDetector( - onTap: () { - if (callback != null) { - callback!([element.pic!.pics!.first.url!], 0); - } else { - context.imageView( - initialPage: 0, - imgList: [ - SourceModel(url: element.pic!.pics!.first.url!) - ], - ); - } - }, - child: NetworkImgLayer( - width: maxWidth, - height: element.pic!.pics!.first.calHeight, - src: element.pic!.pics!.first.url!, - quality: 60, + if (element.pic!.pics!.length == 1) { + element.pic!.pics!.first.onCalHeight(maxWidth); + return Hero( + tag: element.pic!.pics!.first.url!, + child: GestureDetector( + onTap: () { + if (callback != null) { + callback!([element.pic!.pics!.first.url!], 0); + } else { + context.imageView( + initialPage: 0, + imgList: [ + SourceModel(url: element.pic!.pics!.first.url!) + ], + ); + } + }, + child: NetworkImgLayer( + width: maxWidth, + height: element.pic!.pics!.first.calHeight, + src: element.pic!.pics!.first.url!, + quality: 60, + ), ), - ), - ); + ); + } else { + return imageView( + maxWidth, + element.pic!.pics! + .map( + (e) => ImageModel(width: 1, height: 1, url: e.url!)) + .toList()); + } case 3 when (element.line != null): return CachedNetworkImage( width: maxWidth,