diff --git a/android/app/build.gradle b/android/app/build.gradle index 4c258354..262f823b 100644 --- a/android/app/build.gradle +++ b/android/app/build.gradle @@ -51,6 +51,7 @@ android { targetSdkVersion flutter.targetSdkVersion versionCode flutterVersionCode.toInteger() versionName flutterVersionName + minSdkVersion 17 } buildTypes { diff --git a/assets/fonts/fansCard.ttf b/assets/fonts/fansCard.ttf new file mode 100644 index 00000000..09ade3a0 Binary files /dev/null and b/assets/fonts/fansCard.ttf differ diff --git a/lib/common/widgets/network_img_layer.dart b/lib/common/widgets/network_img_layer.dart index ce98c9a9..a09ec850 100644 --- a/lib/common/widgets/network_img_layer.dart +++ b/lib/common/widgets/network_img_layer.dart @@ -30,8 +30,11 @@ class NetworkImgLayer extends StatelessWidget { // double pr = 2; return src != '' ? ClipRRect( - borderRadius: BorderRadius.circular( - type == 'avatar' ? 50 : StyleString.imgRadius.x), + borderRadius: BorderRadius.circular(type == 'avatar' + ? 50 + : type == 'emote' + ? 0 + : StyleString.imgRadius.x), child: CachedNetworkImage( imageUrl: src!, width: width ?? double.infinity, diff --git a/lib/models/video/reply/member.dart b/lib/models/video/reply/member.dart index 196f252b..5576cbd1 100644 --- a/lib/models/video/reply/member.dart +++ b/lib/models/video/reply/member.dart @@ -1,4 +1,4 @@ -import 'dart:convert' as convert; +import 'package:get/get.dart'; class ReplyMember { ReplyMember({ @@ -22,6 +22,7 @@ class ReplyMember { Map? officialVerify; Map? vip; Map? fansDetail; + UserSailing? userSailing; ReplyMember.fromJson(Map json) { mid = json['mid']; @@ -30,9 +31,12 @@ class ReplyMember { avatar = json['avatar']; level = json['level_info']['current_level']; pendant = Pendant.fromJson(json['pendant']); - officialVerify = json['officia_vVerify']; + officialVerify = json['officia_verify']; vip = json['vip']; fansDetail = json['fans_detail']; + userSailing = json['user_sailing'] != null + ? UserSailing.fromJson(json['user_sailing']) + : UserSailing(); } } @@ -53,3 +57,15 @@ class Pendant { image = json['image']; } } + +class UserSailing { + UserSailing({this.pendant, this.cardbg}); + + Map? pendant; + Map? cardbg; + + UserSailing.fromJson(Map json) { + pendant = json['pendant']; + cardbg = json['cardbg']; + } +} diff --git a/lib/pages/video/detail/reply/controller.dart b/lib/pages/video/detail/reply/controller.dart index a82241d5..6e813fc8 100644 --- a/lib/pages/video/detail/reply/controller.dart +++ b/lib/pages/video/detail/reply/controller.dart @@ -23,7 +23,7 @@ class VideoReplyController extends GetxController { // 当前页 int currentPage = 0; bool isLoadingMore = false; - bool noMore = false; + RxBool noMore = false.obs; Future queryReplyList({type = 'init'}) async { isLoadingMore = true; @@ -36,14 +36,17 @@ class VideoReplyController extends GetxController { res['data'] = ReplyData.fromJson(res['data']); if (res['data'].replies.isNotEmpty) { currentPage = currentPage + 1; - noMore = false; + noMore.value = false; } else { if (currentPage == 0) { } else { - noMore = true; + noMore.value = true; return; } } + if (res['data'].replies.length >= res['data'].page.count) { + noMore.value = true; + } if (type == 'init') { List replies = res['data'].replies; // 添加置顶回复 diff --git a/lib/pages/video/detail/reply/view.dart b/lib/pages/video/detail/reply/view.dart index c91ae3fa..e1b2544a 100644 --- a/lib/pages/video/detail/reply/view.dart +++ b/lib/pages/video/detail/reply/view.dart @@ -90,9 +90,10 @@ class _VideoReplyPanelState extends State height: MediaQuery.of(context).padding.bottom + 60, child: Center( - child: Text(_videoReplyController.noMore - ? '没有更多了' - : '加载中'), + child: Obx(() => Text( + _videoReplyController.noMore.value + ? '没有更多了' + : '加载中')), ), ); } else { diff --git a/lib/pages/video/detail/reply/widgets/reply_item.dart b/lib/pages/video/detail/reply/widgets/reply_item.dart index 2faba135..73bafe2f 100644 --- a/lib/pages/video/detail/reply/widgets/reply_item.dart +++ b/lib/pages/video/detail/reply/widgets/reply_item.dart @@ -33,14 +33,42 @@ class ReplyItem extends StatelessWidget { Widget lfAvtar(context) { return Container( - margin: const EdgeInsets.only(top: 5), - child: NetworkImgLayer( - src: replyItem!.member!.avatar, - width: 30, - height: 30, - type: 'avatar', - ), - ); + margin: const EdgeInsets.only(top: 5), + child: Stack( + children: [ + NetworkImgLayer( + src: replyItem!.member!.avatar, + width: 34, + height: 34, + type: 'avatar', + ), + if (replyItem!.member!.officialVerify != null && + replyItem!.member!.officialVerify!['type'] == 0) + Positioned( + right: 0, + bottom: 0, + child: Container( + decoration: BoxDecoration( + borderRadius: BorderRadius.circular(7), + color: Theme.of(context).colorScheme.background, + ), + child: Icon( + Icons.offline_bolt, + color: Theme.of(context).colorScheme.primary, + size: 16, + ), + ), + ), + ], + ) + // child: + // NetworkImgLayer( + // src: replyItem!.member!.avatar, + // width: 30, + // height: 30, + // type: 'avatar', + // ), + ); } Widget content(context) { @@ -54,39 +82,73 @@ class ReplyItem extends StatelessWidget { // 'memberAvatar': reply.avatar, // 'heroTag': reply.userName + heroTag, // }), - child: Row( - crossAxisAlignment: CrossAxisAlignment.center, - mainAxisSize: MainAxisSize.min, - children: [ - lfAvtar(context), - const SizedBox(width: 12), - Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Row( - children: [ - Text( - replyItem!.member!.uname!, - style: TextStyle( - color: replyItem!.isUp! - ? Theme.of(context).colorScheme.primary - : Theme.of(context).colorScheme.outline, - fontSize: - Theme.of(context).textTheme.titleSmall!.fontSize, - ), + child: Container( + width: double.infinity, + decoration: BoxDecoration( + image: replyItem!.member!.userSailing!.cardbg != null + ? DecorationImage( + fit: BoxFit.cover, + image: NetworkImage( + replyItem!.member!.userSailing!.cardbg!['image'], ), - const SizedBox(width: 6), - Image.asset( - 'assets/images/lv/lv${replyItem!.member!.level}.png', - height: 11, + ) + : null, + ), + child: Stack( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + mainAxisSize: MainAxisSize.min, + children: [ + lfAvtar(context), + const SizedBox(width: 12), + Text( + replyItem!.member!.uname!, + style: TextStyle( + color: replyItem!.isUp! || + replyItem!.member!.vip!['vipType'] > 0 + ? Theme.of(context).colorScheme.primary + : Theme.of(context).colorScheme.outline, + fontSize: + Theme.of(context).textTheme.titleSmall!.fontSize, ), - const SizedBox(width: 6), - if (replyItem!.isUp!) UpTag() - ], + ), + const SizedBox(width: 6), + Image.asset( + 'assets/images/lv/lv${replyItem!.member!.level}.png', + height: 11, + ), + const SizedBox(width: 6), + if (replyItem!.isUp!) UpTag(), + ], + ), + if (replyItem!.member!.userSailing!.cardbg != null && + replyItem!.member!.userSailing!.cardbg!['fan']['number'] > + 0) + Positioned( + top: 8, + left: Get.size.width / 7 * 5.6, + child: DefaultTextStyle( + style: TextStyle( + fontFamily: 'fansCard', + fontSize: 9, + color: Theme.of(context).colorScheme.primary, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.center, + children: [ + const Text('NO.'), + Text( + replyItem!.member!.userSailing!.cardbg!['fan'] + ['num_desc'], + ), + ], + ), + ), ), - ], - ) - ], + ], + ), ), ), // title @@ -329,14 +391,16 @@ InlineSpan buildContent(BuildContext context, content) { RegExp(r"\[.*?\]"), onMatch: (Match match) { String matchStr = match[0]!; + int size = content.emote[matchStr]['meta']['size']; if (content.emote.isNotEmpty) { if (content.emote.keys.contains(matchStr)) { spanChilds.add( WidgetSpan( child: NetworkImgLayer( src: content.emote[matchStr]['url'], - width: 20, - height: 20, + type: 'emote', + width: size * 20, + height: size * 20, ), ), ); diff --git a/pubspec.yaml b/pubspec.yaml index efadde4b..7b78fe6a 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -102,17 +102,11 @@ flutter: # "family" key with the font family name, and a "fonts" key with a # list giving the asset and other descriptors for the font. For # example: - # fonts: - # - family: Schyler - # fonts: - # - asset: fonts/Schyler-Regular.ttf - # - asset: fonts/Schyler-Italic.ttf - # style: italic - # - family: Trajan Pro - # fonts: - # - asset: fonts/TrajanPro.ttf - # - asset: fonts/TrajanPro_Bold.ttf - # weight: 700 - # + fonts: + - family: fansCard + fonts: + - asset: assets/fonts/fansCard.ttf + + # For details regarding fonts from package dependencies, # see https://flutter.dev/custom-fonts/#from-packages